# app.py import os from fastapi import FastAPI, HTTPException from pydantic import BaseModel from huggingface_hub import hf_hub_download from llama_cpp import Llama # llama-cpp-python をインポート # ----------------------------------------------------------------------------- # Hugging Face Hub の設定 # ----------------------------------------------------------------------------- HF_TOKEN = os.environ.get("HF_TOKEN") # 必要に応じて Secrets にセット REPO_ID = "google/gemma-3-4b-it-qat-q4_0-gguf" # 実際にリポジトリに置かれている GGUF ファイル名を確認してください。 # 例: "gemma-3-4b-it-qat-q4_0-gguf.gguf" GGUF_FILENAME = "gemma-3-4b-it-q4_0.gguf" # キャッシュ先のパス(リポジトリ直下に置く場合) MODEL_PATH = os.path.join(os.getcwd(), GGUF_FILENAME) # ----------------------------------------------------------------------------- # 起動時に一度だけダウンロード # ----------------------------------------------------------------------------- if not os.path.exists(MODEL_PATH): print(f"Downloading {GGUF_FILENAME} from {REPO_ID} …") hf_hub_download( repo_id=REPO_ID, filename=GGUF_FILENAME, token=HF_TOKEN, repo_type="model", # 明示的にモデルリポジトリを指定 local_dir=os.getcwd(), # カレントディレクトリに保存 local_dir_use_symlinks=False ) # ----------------------------------------------------------------------------- # llama-cpp-python で 4bit GGUF モデルをロード # ----------------------------------------------------------------------------- print(f"Loading model from {MODEL_PATH}...") try: llm = Llama( model_path=MODEL_PATH, n_ctx=2048, # コンテキストサイズ (モデルに合わせて調整してください) # n_gpu_layers=-1, # GPU を使う場合 (Hugging Face Spaces 無料枠では通常 0) n_gpu_layers=0, # CPU のみ使用 verbose=True # 詳細ログを出力 ) print("Model loaded successfully.") except Exception as e: print(f"Error loading model: {e}") # エラーが発生した場合、アプリケーションを終了させるか、エラーハンドリングを行う # ここでは簡単なエラーメッセージを出力して終了する例 raise RuntimeError(f"Failed to load the LLM model: {e}") # ----------------------------------------------------------------------------- # FastAPI 定義 # ----------------------------------------------------------------------------- app = FastAPI(title="Gemma3-4B-IT Q4_0 GGUF API") @app.get("/") async def read_root(): return {"message": "Gemma3 API is running"} class GenerationRequest(BaseModel): prompt: str max_new_tokens: int = 128 temperature: float = 0.8 top_p: float = 0.95 # llama-cpp-python で利用可能な他のパラメータも追加可能 # stop: list[str] | None = None # repeat_penalty: float = 1.1 @app.post("/generate") async def generate(req: GenerationRequest): if not req.prompt: raise HTTPException(status_code=400, detail="`prompt` は必須です。") try: # llama-cpp-python の __call__ メソッドで生成 output = llm( req.prompt, max_tokens=req.max_new_tokens, temperature=req.temperature, top_p=req.top_p, # stop=req.stop, # 必要なら追加 # repeat_penalty=req.repeat_penalty, # 必要なら追加 ) # 生成されたテキストを取得 generated_text = output["choices"][0]["text"] return {"generated_text": generated_text} except Exception as e: print(f"Error during generation: {e}") raise HTTPException(status_code=500, detail=f"生成中にエラーが発生しました: {e}") # ----------------------------------------------------------------------------- # Uvicorn サーバーの起動 (Hugging Face Spaces 用) # ----------------------------------------------------------------------------- # if __name__ == "__main__": ガードは付けずに直接実行 import uvicorn # Hugging Face Spaces で標準的に使用されるポート 7860 を明示的に指定 port = 7860 # port = int(os.environ.get("PORT", 7860)) # 環境変数があればそれを使う方が良い場合もある # host="0.0.0.0" でコンテナ外からのアクセスを許可 uvicorn.run(app, host="0.0.0.0", port=port, log_level="info")