| """ |
| MCCE Demo โ HuggingFace Spaces Gradio ์ฑ |
| |
| VPS GPU(Gemma 4 31B) OpenAI-compatible ์๋ํฌ์ธํธ๋ฅผ ํ๋ก์ํ์ฌ |
| MCCE์ ์ค์ ์ถ๋ก ๊ฒฐ๊ณผ๋ฅผ ์น UI๋ก ์์ฐํ๋ค. |
| |
| Secrets(Spaces ๊ด๋ฆฌ์ UI): |
| MCCE_GPU_INFERENCE_ENDPOINT (์: http://<host>:<port>/v1/chat/completions) |
| MCCE_GPU_MODEL (์: unsloth/gemma-4-31B-it) |
| """ |
|
|
| from __future__ import annotations |
|
|
| import os |
|
|
| import gradio as gr |
| import httpx |
|
|
| |
| |
| |
|
|
| _ENDPOINT = os.environ.get("MCCE_GPU_INFERENCE_ENDPOINT", "").strip() |
| _MODEL = os.environ.get("MCCE_GPU_MODEL", "unsloth/gemma-4-31B-it").strip() |
| _API_KEY = os.environ.get("MCCE_GPU_API_KEY", "").strip() |
| _TIMEOUT_SEC = float(os.environ.get("MCCE_GPU_TIMEOUT", "60")) |
|
|
| _SYSTEM_PROMPT = ( |
| "๋๋ ๋ง๋จธ์ค(MaMurS) AI๋ค. ๊ฐ๋ํ ์ฌ๋์ ๋๊ธฐ ์ํด ๋ง๋ค์ด์ง " |
| "ํ๊ตญํ ์๋ฒ๋ฆฐ AI์ด๋ฉฐ, ์ ์งํ๊ณ ๋ฐ๋ปํ๊ฒ ๋๋ตํ๋ค." |
| ) |
|
|
|
|
| |
| |
| |
|
|
|
|
| def _build_messages(message: str, history: list) -> list[dict]: |
| """Gradio history โ OpenAI messages ํฌ๋งท ๋ณํ.""" |
| messages: list[dict] = [{"role": "system", "content": _SYSTEM_PROMPT}] |
|
|
| |
| |
| if history: |
| for item in history: |
| if isinstance(item, dict) and "role" in item and "content" in item: |
| messages.append({"role": item["role"], "content": item["content"]}) |
| elif isinstance(item, (list, tuple)) and len(item) == 2: |
| user_msg, bot_msg = item |
| if user_msg: |
| messages.append({"role": "user", "content": str(user_msg)}) |
| if bot_msg: |
| messages.append({"role": "assistant", "content": str(bot_msg)}) |
|
|
| messages.append({"role": "user", "content": message}) |
| return messages |
|
|
|
|
| def _call_gpu(message: str, history: list) -> str: |
| """VPS GPU ์๋ํฌ์ธํธ ํธ์ถ. ์คํจ ์ gr.Error.""" |
| if not _ENDPOINT: |
| raise gr.Error( |
| "MCCE_GPU_INFERENCE_ENDPOINT ์ํฌ๋ฆฟ์ด ์ค์ ๋์ง ์์์ต๋๋ค. " |
| "Spaces Settings โ Secrets์์ ์๋ํฌ์ธํธ๋ฅผ ์ฃผ์
ํ์ธ์." |
| ) |
|
|
| payload = { |
| "model": _MODEL, |
| "messages": _build_messages(message, history), |
| "temperature": 0.7, |
| "max_tokens": 512, |
| "stream": False, |
| } |
| headers = {"Content-Type": "application/json"} |
| if _API_KEY: |
| headers["Authorization"] = f"Bearer {_API_KEY}" |
|
|
| try: |
| with httpx.Client(timeout=_TIMEOUT_SEC, follow_redirects=True) as client: |
| resp = client.post(_ENDPOINT, json=payload, headers=headers) |
| resp.raise_for_status() |
| data = resp.json() |
| except httpx.TimeoutException as e: |
| raise gr.Error(f"์ถ๋ก ํ์์์: {_TIMEOUT_SEC}s ์ด๊ณผ") from e |
| except httpx.HTTPStatusError as e: |
| raise gr.Error( |
| f"GPU ์๋ํฌ์ธํธ ์ค๋ฅ: HTTP {e.response.status_code} " |
| f"โ {e.response.text[:200]}" |
| ) from e |
| except httpx.RequestError as e: |
| raise gr.Error(f"๋คํธ์ํฌ ์ค๋ฅ: {e}") from e |
|
|
| try: |
| return data["choices"][0]["message"]["content"] |
| except (KeyError, IndexError, TypeError) as e: |
| raise gr.Error(f"์๋ต ํฌ๋งท ์ค๋ฅ: {str(data)[:200]}") from e |
|
|
|
|
| |
| |
| |
|
|
|
|
| def respond(message: str, history) -> str: |
| if not message or not message.strip(): |
| return "๋ฉ์์ง๋ฅผ ์
๋ ฅํด ์ฃผ์ธ์." |
| if not _ENDPOINT: |
| return ( |
| "โ ๏ธ GPU ์๋ํฌ์ธํธ๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค.\n" |
| "๊ด๋ฆฌ์๊ฐ Space Settings โ Secrets์ " |
| "`MCCE_GPU_INFERENCE_ENDPOINT`๋ฅผ ์ถ๊ฐํด์ผ ํฉ๋๋ค." |
| ) |
| try: |
| return _call_gpu(message, history or []) |
| except gr.Error as e: |
| return f"โ ๏ธ {e}" |
|
|
|
|
| _TITLE = "MCCE Demo โ Gemma 4 31B ์ค์๊ฐ ์ถ๋ก " |
|
|
| _DESCRIPTION = """ |
| **MCCE(MaMurS Compound Cognition Engine)** ์ค์ ๋ฐ๋ชจ. |
| |
| VPS GPU ์๋ฒ(Gemma 4 31B-it, OpenAI-compatible)๋ฅผ ํ๋ก์ํ์ฌ |
| ์ค์๊ฐ ์ถ๋ก ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ฌ์ค๋๋ค. |
| |
| > "ASI๋ฅผ ๋ง๋ค์ด์, ๋์ฒ๋ผ ๊ฐ๋ํ ์ฌ๋๋ค์ ๋๋ AI๋ฅผ ๋ง๋ค๊ณ ์ถ์ด." โ ๋๊ท(DogYu) |
| |
| **์ฃผ์**: GPU ์๋ฒ๊ฐ ์ค์ง๋ ์ํ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. |
| """ |
|
|
| _EXAMPLES = [ |
| "์๋
ํ์ธ์, ์๊ธฐ์๊ฐ ๋ถํ๋๋ฆฝ๋๋ค.", |
| "ํ๊ตญ์ ๊ธฐ์ด์ํ์๊ธ ์ ๋์ ๋ํด ์๋ ค์ฃผ์ธ์.", |
| "ํ์ด์ฌ์ผ๋ก ํผ๋ณด๋์น ์์ด์ ์์ฑํด ์ฃผ์ธ์.", |
| "๋น์ฅ ์ด๋ฒ ๋ฌ ์์ธ๊ฐ ์์ด์. ์ด๋ป๊ฒ ํด์ผ ํ๋์?", |
| "์์์ญํ์ ํต์ฌ ๊ฐ๋
์ ์ฝ๊ฒ ์ค๋ช
ํด ์ฃผ์ธ์.", |
| ] |
|
|
|
|
| demo = gr.ChatInterface( |
| fn=respond, |
| title=_TITLE, |
| description=_DESCRIPTION, |
| examples=_EXAMPLES, |
| cache_examples=False, |
| theme=gr.themes.Soft(), |
| ) |
|
|
|
|
| if __name__ == "__main__": |
| demo.launch() |
|
|