| import gradio as gr |
| from azure.ai.inference import ChatCompletionsClient |
| from azure.ai.inference.models import SystemMessage, UserMessage, AssistantMessage |
| from azure.core.credentials import AzureKeyCredential |
|
|
|
|
| def _normalize_endpoint(endpoint: str) -> str: |
| """ |
| ChatCompletionsClient expects the Azure AI inference endpoint that ends with /models. |
| Many UIs show a "project endpoint" or a resource endpoint without /models. |
| This function tries to normalize what the user pastes into a usable inference endpoint. |
| """ |
| endpoint = (endpoint or "").strip() |
| if not endpoint: |
| raise gr.Error("Please provide an Azure/Microsoft Foundry endpoint.") |
|
|
| if not endpoint.startswith("http"): |
| endpoint = "https://" + endpoint |
|
|
| endpoint = endpoint.rstrip("/") |
|
|
| |
| if ".services.ai.azure.com" in endpoint and not endpoint.endswith("/models"): |
| endpoint = endpoint + "/models" |
|
|
| return endpoint |
|
|
|
|
| def _build_client(endpoint: str, api_key: str) -> ChatCompletionsClient: |
| api_key = (api_key or "").strip() |
| if not api_key: |
| raise gr.Error("Please provide an API key.") |
|
|
| endpoint = _normalize_endpoint(endpoint) |
| return ChatCompletionsClient(endpoint=endpoint, credential=AzureKeyCredential(api_key)) |
|
|
|
|
| def _to_messages(system_prompt: str, history: list[tuple[str, str]], user_text: str): |
| msgs = [] |
| system_prompt = (system_prompt or "").strip() |
| if system_prompt: |
| msgs.append(SystemMessage(content=system_prompt)) |
|
|
| for u, a in (history or []): |
| if u: |
| msgs.append(UserMessage(content=u)) |
| if a: |
| msgs.append(AssistantMessage(content=a)) |
|
|
| msgs.append(UserMessage(content=(user_text or ""))) |
| return msgs |
|
|
|
|
| def chat( |
| endpoint: str, |
| api_key: str, |
| model: str, |
| system_prompt: str, |
| temperature: float, |
| max_tokens: int, |
| top_p: float, |
| user_text: str, |
| history: list[tuple[str, str]], |
| ): |
| user_text = (user_text or "").strip() |
| if not user_text: |
| return "", history, "" |
|
|
| |
| client = _build_client(endpoint, api_key) |
|
|
| |
| |
| model = (model or "").strip() |
| if not model: |
| raise gr.Error("Please provide a model/deployment name (e.g., your deployment for gpt-4o).") |
|
|
| try: |
| resp = client.complete( |
| model=model, |
| messages=_to_messages(system_prompt, history, user_text), |
| temperature=float(temperature), |
| max_tokens=int(max_tokens), |
| top_p=float(top_p), |
| ) |
| answer = resp.choices[0].message.content or "" |
| used_endpoint = client._endpoint |
| info = f"✅ Called: {used_endpoint}\n✅ Model/Deployment: {model}" |
| except Exception as e: |
| raise gr.Error( |
| "Azure call failed.\n\n" |
| "Most common fixes:\n" |
| "1) Ensure your endpoint is the Azure AI inference endpoint (it should end with /models).\n" |
| "2) Ensure the key matches that same resource/project.\n" |
| "3) Ensure 'Model/Deployment' is your DEPLOYMENT NAME in Foundry.\n\n" |
| f"Error: {type(e).__name__}: {e}" |
| ) |
|
|
| history = (history or []) + [(user_text, answer)] |
| return "", history, info |
|
|
|
|
| def clear_all(): |
| return [], "" |
|
|
|
|
| with gr.Blocks(title="Azure (Foundry) GPT-4o Chatbot") as demo: |
| gr.Markdown( |
| "## Azure / Microsoft Foundry Chatbot\n" |
| "**Tip:** Your endpoint must be the Azure AI inference endpoint. If you paste a Foundry resource endpoint like\n" |
| "`https://xxxx.services.ai.azure.com`, this app will automatically append `/models`.\n\n" |
| "**Model/Deployment:** often must be your **deployment name** (even if the base model is GPT-4o)." |
| ) |
|
|
| with gr.Row(): |
| with gr.Column(scale=4): |
| chatbot = gr.Chatbot(height=520) |
| user_text = gr.Textbox( |
| label="Message", |
| placeholder="Type your message and press Enter…", |
| lines=2, |
| ) |
| with gr.Row(): |
| send = gr.Button("Send", variant="primary") |
| clear = gr.Button("Clear chat") |
|
|
| with gr.Column(scale=3): |
| with gr.Accordion("Connection (Endpoint + Key)", open=True): |
| endpoint = gr.Textbox( |
| label="Azure endpoint (Foundry resource or inference endpoint)", |
| placeholder="https://projectxxxxx-resource.services.ai.azure.com (app will add /models)", |
| ) |
| api_key = gr.Textbox( |
| label="API key", |
| placeholder="Paste your key here", |
| type="password", |
| ) |
|
|
| with gr.Accordion("Model + generation settings", open=True): |
| model = gr.Textbox( |
| label="Model / Deployment name", |
| value="gpt-4o", |
| info="If you get 'model not found', change this to your deployment name from Foundry." |
| ) |
| system_prompt = gr.Textbox( |
| label="System prompt (optional)", |
| value="You are a helpful assistant.", |
| lines=3, |
| ) |
| temperature = gr.Slider(0, 1.5, value=0.7, step=0.1, label="Temperature") |
| max_tokens = gr.Slider(64, 4096, value=1024, step=64, label="Max tokens") |
| top_p = gr.Slider(0.1, 1.0, value=1.0, step=0.05, label="Top-p") |
|
|
| debug_info = gr.Textbox( |
| label="Debug info", |
| value="", |
| interactive=False, |
| lines=3, |
| ) |
|
|
| send.click( |
| chat, |
| inputs=[endpoint, api_key, model, system_prompt, temperature, max_tokens, top_p, user_text, chatbot], |
| outputs=[user_text, chatbot, debug_info], |
| ) |
| user_text.submit( |
| chat, |
| inputs=[endpoint, api_key, model, system_prompt, temperature, max_tokens, top_p, user_text, chatbot], |
| outputs=[user_text, chatbot, debug_info], |
| ) |
|
|
| clear.click(clear_all, outputs=[chatbot, debug_info]) |
|
|
| demo.launch(server_name="0.0.0.0", server_port=7860) |
|
|