Spaces:
Runtime error
Runtime error
| """ | |
| Naveed AI β Fast Conversational Chat | |
| Built by Naveed Khan | Powered by Qwen2.5 | Free Forever | |
| """ | |
| import os | |
| import re | |
| import json | |
| # ββ Speed: silence tokenizer noise ββββββββββββββββββββββββββββββββββββββββββββ | |
| os.environ.setdefault("TOKENIZERS_PARALLELISM", "false") | |
| # ββ Bootstrap βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print("π Starting Naveed AIβ¦", flush=True) | |
| from config import get_config | |
| from model_loader import ModelLoader | |
| from inference import InferenceEngine | |
| cfg = get_config() | |
| _loader = ModelLoader(cfg) | |
| print(f"π¦ Loading model: {cfg.model.default_model}", flush=True) | |
| _loader.load(model_id=cfg.model.default_model, auto_download=True) | |
| print("β Model ready!", flush=True) | |
| engine = InferenceEngine(_loader, cfg) | |
| # ββ Gradio βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| import gradio as gr | |
| try: | |
| GRADIO_MAJOR = int(str(gr.__version__).split(".")[0]) | |
| except Exception: | |
| GRADIO_MAJOR = 4 | |
| USE_MSG_FMT = GRADIO_MAJOR >= 5 # message-dict format (v5/v6) vs tuple format (v4) | |
| # Gradio 6 removed type= param β messages format is always the default | |
| USE_TYPE_PARAM = (4 < GRADIO_MAJOR < 6) # only Gradio 5.x needs explicit type="messages" | |
| print(f"π¨ Gradio {gr.__version__} β {'messages' if USE_MSG_FMT else 'tuples'} mode", flush=True) | |
| # ββ Helpers ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _text(content) -> str: | |
| """Normalise any Gradio message content β plain string.""" | |
| if content is None: | |
| return "" | |
| if isinstance(content, str): | |
| return content | |
| if isinstance(content, (int, float, bool)): | |
| return str(content) | |
| if isinstance(content, list): | |
| return " ".join(_text(i) for i in content if _text(i)).strip() | |
| if isinstance(content, dict): | |
| return _text(content.get("text") or content.get("content") or "") | |
| return str(content) | |
| def _render_think(text: str) -> str: | |
| """Convert <think>β¦</think> blocks into a readable quote.""" | |
| def _block(m): | |
| thought = m.group(1).strip() | |
| return f"\n\nπ *Thinking:*\n> {thought}\n\n---\n\n" | |
| return re.sub(r"<think>(.*?)</think>", _block, text, flags=re.DOTALL) | |
| # ββ Chat function ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def chat_fn(message: str, history): | |
| """ | |
| Real-time streaming chat. | |
| - history is a list of message-dicts (v5+) or [user, assistant] tuples (v4). | |
| - Yields updated history after every token so the UI streams live. | |
| """ | |
| message = message.strip() | |
| if not message: | |
| yield history | |
| return | |
| # Build messages list: system + trimmed history + new user turn | |
| sys_prompt = cfg.conversation.system_prompt | |
| messages = [{"role": "system", "content": sys_prompt}] | |
| max_turns = cfg.conversation.max_history_turns | |
| recent = history[-max_turns:] if len(history) > max_turns else history | |
| for item in recent: | |
| if USE_MSG_FMT: | |
| role = item.get("role", "user") | |
| content = _text(item.get("content", "")) | |
| if content and role in ("user", "assistant"): | |
| messages.append({"role": role, "content": content}) | |
| else: | |
| u = _text(item[0]) if len(item) > 0 else "" | |
| a = _text(item[1]) if len(item) > 1 else "" | |
| if u: | |
| messages.append({"role": "user", "content": u}) | |
| if a: | |
| messages.append({"role": "assistant", "content": a}) | |
| messages.append({"role": "user", "content": message}) | |
| # Append user turn to display history | |
| if USE_MSG_FMT: | |
| history = list(history) + [{"role": "user", "content": message}] | |
| else: | |
| history = list(history) + [[message, None]] | |
| # Stream assistant reply token-by-token | |
| response = "" | |
| try: | |
| for token in engine.chat_generate(messages, stream=True): | |
| response += token | |
| # Only run regex if <think> tag is present (avoids regex overhead on every token) | |
| rendered = _render_think(response) if "<think>" in response else response | |
| if USE_MSG_FMT: | |
| yield history + [{"role": "assistant", "content": rendered}] | |
| else: | |
| yield history[:-1] + [[message, rendered]] | |
| except Exception as exc: | |
| err = f"β οΈ Sorry, something went wrong: {exc}" | |
| if USE_MSG_FMT: | |
| yield history + [{"role": "assistant", "content": err}] | |
| else: | |
| yield history[:-1] + [[message, err]] | |
| return | |
| # Commit final clean turn | |
| final = _render_think(response) if "<think>" in response else response | |
| if USE_MSG_FMT: | |
| yield history + [{"role": "assistant", "content": final}] | |
| else: | |
| yield history[:-1] + [[message, final]] | |
| # ββ CSS ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| CSS = """ | |
| .gradio-container { | |
| max-width: 860px !important; | |
| margin: auto !important; | |
| font-family: 'Inter', 'Segoe UI', system-ui, sans-serif !important; | |
| } | |
| footer { display: none !important; } | |
| .header-wrap { | |
| background: linear-gradient(135deg, #0f0c29 0%, #302b63 50%, #24243e 100%); | |
| border-radius: 16px; | |
| padding: 24px 32px 20px; | |
| margin-bottom: 12px; | |
| text-align: center; | |
| border: 1px solid #7c3aed33; | |
| } | |
| .header-wrap h1 { | |
| background: linear-gradient(135deg, #a78bfa, #60a5fa, #34d399); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| font-size: 2.3em; | |
| margin: 0 0 4px; | |
| font-weight: 800; | |
| letter-spacing: -0.6px; | |
| } | |
| .header-wrap p { color: #94a3b8; margin: 0; font-size: 0.96em; } | |
| .dot { | |
| display: inline-block; | |
| width: 8px; height: 8px; | |
| border-radius: 50%; | |
| background: #22c55e; | |
| margin-right: 6px; | |
| vertical-align: middle; | |
| animation: blink 2s infinite; | |
| } | |
| @keyframes blink { 0%,100%{opacity:1;} 50%{opacity:.35;} } | |
| #send-btn { | |
| background: #111827 !important; | |
| color: #fff !important; | |
| border-radius: 10px !important; | |
| font-weight: 600 !important; | |
| min-height: 48px !important; | |
| } | |
| #send-btn:hover { background: #1f2937 !important; } | |
| #clear-btn { border-radius: 10px !important; } | |
| /* API snippet accordion */ | |
| .api-accordion { | |
| margin-top: 10px; | |
| border: 1px solid #334155 !important; | |
| border-radius: 12px !important; | |
| background: #0f172a !important; | |
| } | |
| .api-accordion .label-wrap span { | |
| font-size: 0.9em !important; | |
| color: #94a3b8 !important; | |
| font-weight: 500 !important; | |
| } | |
| .api-tabs .tab-nav button { | |
| font-size: 0.82em !important; | |
| padding: 4px 10px !important; | |
| } | |
| .api-code pre { | |
| font-size: 0.82em !important; | |
| border-radius: 8px !important; | |
| background: #1e293b !important; | |
| } | |
| """ | |
| # ββ Gradio UI ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| with gr.Blocks(title="Naveed AI") as demo: | |
| # ββ Header ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| gr.HTML(""" | |
| <div class="header-wrap"> | |
| <h1>π§ Naveed AI</h1> | |
| <p> | |
| <span class="dot"></span> | |
| Built by <strong style="color:#c4b5fd">Naveed Khan</strong> | |
| Β· Smart Β· Fast Β· Free Forever | |
| </p> | |
| </div> | |
| """) | |
| # ββ Chatbot βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| bot_kwargs = dict( | |
| value=[], | |
| show_label=False, | |
| height=520, | |
| ) | |
| if USE_TYPE_PARAM: | |
| bot_kwargs["type"] = "messages" | |
| chatbot = gr.Chatbot(**bot_kwargs) | |
| # ββ Input row βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| with gr.Row(): | |
| msg = gr.Textbox( | |
| placeholder="Message Naveed AIβ¦", | |
| show_label=False, | |
| scale=9, | |
| container=False, | |
| autofocus=True, | |
| lines=1, | |
| max_lines=6, | |
| elem_id="msg-input", | |
| ) | |
| send = gr.Button("Send β€", elem_id="send-btn", scale=1, min_width=90) | |
| # Rotating placeholder via JS injected into page | |
| gr.HTML(""" | |
| <script> | |
| (function() { | |
| const hints = [ | |
| "Message Naveed AIβ¦", | |
| "Ask me anythingβ¦", | |
| "What\u2019s on your mind?", | |
| "Try: \"Explain AI in simple words\"", | |
| "Try: \"Write me a Python script\"", | |
| "Try: \"Give me a workout plan\"", | |
| "Try: \"Help me write a cover letter\"", | |
| "Try: \"What is quantum computing?\"", | |
| "Try: \"Is this news headline real?\"", | |
| ]; | |
| let i = 0; | |
| function rotatePlaceholder() { | |
| const input = document.querySelector('#msg-input textarea'); | |
| if (input && !input.value) { | |
| i = (i + 1) % hints.length; | |
| input.setAttribute('placeholder', hints[i]); | |
| } | |
| } | |
| setInterval(rotatePlaceholder, 3000); | |
| })(); | |
| </script> | |
| """) | |
| # ββ Controls ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| with gr.Row(): | |
| clear = gr.Button("π Clear chat", variant="secondary", | |
| size="sm", elem_id="clear-btn", scale=1) | |
| gr.HTML('<div style="flex:4"></div>') # spacer | |
| # ββ Starter examples ββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| gr.Examples( | |
| label="π‘ Try askingβ¦", | |
| examples=[ | |
| ["Who are you and what can you do?"], | |
| ["Explain quantum computing like I'm 10 years old"], | |
| ["Write a Python script to fetch today's Bitcoin price"], | |
| ["Give me a 7-day workout plan for a beginner"], | |
| ["Help me write a resignation letter β professional but friendly"], | |
| ["I heard coffee causes cancer. Is that true?"], | |
| ["What are the top 5 habits of highly successful people?"], | |
| ["Tell me something fascinating about the universe"], | |
| ], | |
| inputs=msg, | |
| ) | |
| # ββ API code snippets (collapsible) βββββββββββββββββββββββββββββββββββββββββββββββββ | |
| with gr.Accordion("π Use Naveed AI in your own app β free API", open=False, | |
| elem_classes=["api-accordion"]): | |
| with gr.Tabs(elem_classes=["api-tabs"]): | |
| with gr.TabItem("π Python"): | |
| gr.Code( | |
| value='''from gradio_client import Client | |
| client = Client("bilalnaveed/Naveedai") | |
| # Single message | |
| result = client.predict( | |
| message="What are the top habits of successful people?", | |
| history=[], | |
| api_name="/chat_fn" | |
| ) | |
| print(result[-1]["content"]) # last assistant reply | |
| # Multi-turn conversation | |
| history = [] | |
| def ask(msg): | |
| global history | |
| history = client.predict(message=msg, history=history, api_name="/chat_fn") | |
| last = history[-1] | |
| return last.get("content", "") if isinstance(last, dict) else last[1] | |
| print(ask("Hello!")) | |
| print(ask("Tell me a fun science fact")) | |
| ''', | |
| language="python", | |
| elem_classes=["api-code"], | |
| interactive=False, | |
| ) | |
| with gr.TabItem("π JavaScript"): | |
| gr.Code( | |
| value='''// Works in browser or Node.js β no API key needed | |
| async function askNaveedAI(message, history = []) { | |
| const res = await fetch( | |
| "https://bilalnaveed-naveedai.hf.space/run/predict", | |
| { | |
| method: "POST", | |
| headers: { "Content-Type": "application/json" }, | |
| body: JSON.stringify({ data: [message, history] }), | |
| } | |
| ); | |
| const json = await res.json(); | |
| const updatedHistory = json.data[0]; // full history array | |
| const lastMsg = updatedHistory[updatedHistory.length - 1]; | |
| return typeof lastMsg === "object" && lastMsg.content | |
| ? lastMsg.content | |
| : lastMsg[1]; // tuple fallback | |
| } | |
| // Usage | |
| askNaveedAI("Explain machine learning in 2 sentences").then(console.log); | |
| ''', | |
| language="javascript", | |
| elem_classes=["api-code"], | |
| interactive=False, | |
| ) | |
| with gr.TabItem("π» cURL"): | |
| gr.Code( | |
| value='''# Call from any terminal β completely free | |
| curl -X POST "https://bilalnaveed-naveedai.hf.space/run/predict" \\ | |
| -H "Content-Type: application/json" \\ | |
| -d \'{"data": ["Who are you?", []]}\'\n''', | |
| language="shell", | |
| elem_classes=["api-code"], | |
| interactive=False, | |
| ) | |
| # ββ Events ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| send.click(chat_fn, [msg, chatbot], [chatbot]).then( | |
| lambda: gr.update(value=""), None, [msg] | |
| ) | |
| msg.submit(chat_fn, [msg, chatbot], [chatbot]).then( | |
| lambda: gr.update(value=""), None, [msg] | |
| ) | |
| clear.click(lambda: [], None, [chatbot]) | |
| # ββ Launch βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| demo.queue(max_size=15).launch( | |
| server_name="0.0.0.0", | |
| server_port=int(os.environ.get("PORT", 7860)), | |
| show_error=True, | |
| quiet=False, | |
| theme=gr.themes.Soft( | |
| primary_hue="violet", | |
| secondary_hue="blue", | |
| neutral_hue="slate", | |
| font=gr.themes.GoogleFont("Inter"), | |
| ), | |
| css=CSS, | |
| ) | |