File size: 3,528 Bytes
512e442
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Gradio UI + FastAPI mount. Entry point cho HuggingFace Spaces."""
from __future__ import annotations
import os
from dotenv import load_dotenv
import gradio as gr
from fastapi import FastAPI
from pydantic import BaseModel

load_dotenv()

from app.agent import build_agent
from app.llm import PROVIDERS, available_providers

# ---------- FastAPI ----------
api = FastAPI(title="Tan's Agent API")


class ChatReq(BaseModel):
    message: str
    provider: str = os.getenv("DEFAULT_PROVIDER", "gemini")
    model: str | None = None


@api.get("/health")
def health():
    return {"status": "ok", "providers_ready": available_providers()}


@api.post("/chat")
def chat_api(req: ChatReq):
    agent = build_agent(provider=req.provider, model=req.model)
    out = agent.invoke({"input": req.message})
    return {"response": out.get("output", "")}


# ---------- Gradio UI ----------
def respond(message, history, provider, model):
    if not message:
        return "Vui lòng nhập câu hỏi."
    try:
        agent = build_agent(provider=provider, model=model or None)
        # Chuyển history (list of [user, assistant]) -> messages
        chat_history = []
        for turn in history or []:
            if isinstance(turn, (list, tuple)) and len(turn) == 2:
                u, a = turn
                if u:
                    chat_history.append(("human", u))
                if a:
                    chat_history.append(("ai", a))
        result = agent.invoke({"input": message, "chat_history": chat_history})
        return result.get("output", "(không có phản hồi)")
    except Exception as e:
        return f"⚠️ Lỗi: {e}"


def update_models(provider):
    models = PROVIDERS.get(provider, {}).get("models", [])
    default = PROVIDERS.get(provider, {}).get("default", models[0] if models else "")
    return gr.update(choices=models, value=default)


with gr.Blocks(title="Tan's AI Agent", theme=gr.themes.Soft()) as demo:
    gr.Markdown(
        "# 🤖 Tan's AI Agent\n"
        "Multi-provider ReAct agent với web search, calculator, time tool. "
        "Tất cả model đều **miễn phí**."
    )
    ready = available_providers()
    if not ready:
        gr.Markdown(
            "### ⚠️ Chưa có API key\n"
            "Vào tab **Settings → Variables and secrets** của HF Space và thêm 1 trong: "
            "`GOOGLE_API_KEY`, `GROQ_API_KEY`, `GITHUB_TOKEN`."
        )

    with gr.Row():
        provider_dd = gr.Dropdown(
            choices=list(PROVIDERS.keys()),
            value=ready[0] if ready else "gemini",
            label="Provider",
            scale=1,
        )
        model_dd = gr.Dropdown(
            choices=PROVIDERS[ready[0] if ready else "gemini"]["models"],
            value=PROVIDERS[ready[0] if ready else "gemini"]["default"],
            label="Model",
            scale=2,
        )

    provider_dd.change(update_models, inputs=provider_dd, outputs=model_dd)

    chat = gr.ChatInterface(
        fn=respond,
        additional_inputs=[provider_dd, model_dd],
        examples=[
            ["Bây giờ là mấy giờ?"],
            ["Tin tức mới nhất về AI hôm nay?"],
            ["Tính giúp tôi (1234 * 5678) + 999"],
            ["Giải thích Transformer trong 3 câu"],
        ],
    )

# Mount Gradio vào FastAPI tại "/"
app = gr.mount_gradio_app(api, demo, path="/")


if __name__ == "__main__":
    import uvicorn
    port = int(os.getenv("PORT", "7860"))
    uvicorn.run(app, host="0.0.0.0", port=port)