Spaces:
Running
Running
| import os | |
| # ২ vCPU-তে বাড়তি থ্রেড (BLAS/OpenMP) খোলা বন্ধ রাখতে Llama() লোডের আগেই সেট করতে হবে | |
| os.environ["OMP_NUM_THREADS"] = "2" | |
| os.environ["OPENBLAS_NUM_THREADS"] = "2" | |
| import gradio as gr | |
| from huggingface_hub import hf_hub_download | |
| from llama_cpp import Llama | |
| import time | |
| # ======================== | |
| # ১. মডেল ডাউনলোড | |
| # ======================== | |
| #MODEL_REPO = "prism-ml/Bonsai-8B-gguf" | |
| #MODEL_FILE = "Bonsai-8B-Q1_0.gguf" | |
| #MODEL_REPO = "prism-ml/Bonsai-27B-gguf" | |
| #MODEL_FILE = "Bonsai-27B-Q1_0.gguf" | |
| MODEL_REPO = "prism-ml/Bonsai-1.7B-gguf" | |
| MODEL_FILE = "Bonsai-1.7B-Q1_0.gguf" | |
| print("📥 মডেল ডাউনলোড হচ্ছে...") | |
| model_path = hf_hub_download( | |
| repo_id=MODEL_REPO, | |
| filename=MODEL_FILE, | |
| local_dir="./models" | |
| ) | |
| print("✅ মডেল ডাউনলোড সম্পূর্ণ!") | |
| # ======================== | |
| # ২. LLM লোড করুন | |
| # HF Spaces free tier: 2 vCPU, 16GB RAM, no GPU | |
| # ======================== | |
| llm = Llama( | |
| model_path=model_path, | |
| n_ctx=1024, # কমানো হলো — MAX_TURNS দিয়ে history ছোট রাখা হচ্ছে, তাই বড় ctx দরকার নেই | |
| n_threads=2, | |
| n_threads_batch=2, | |
| n_batch=128, | |
| n_gpu_layers=0, | |
| use_mmap=True, | |
| use_mlock=False, | |
| # NOTE: quantized KV cache (type_k/type_v = Q8_0) বাদ দেওয়া হলো — | |
| # এটার জন্য flash_attn=True লাগে, আর CPU build-এ flash attention প্রায়ই | |
| # অসমর্থিত/অস্থিতিশীল, ফলে "Failed to create llama_context" এরর হয়েছিল। | |
| verbose=False, | |
| ) | |
| print("🔥 মডেল ওয়ার্ম-আপ হচ্ছে...") | |
| try: | |
| list(llm("Hi", max_tokens=1, stream=False)) | |
| except Exception as e: | |
| print(f"ওয়ার্ম-আপ স্কিপ হলো: {e}") | |
| print("✅ ওয়ার্ম-আপ সম্পূর্ণ, সার্ভার রেডি!") | |
| # ======================== | |
| # ৩. চ্যাট ফাংশন (স্ট্রিমিং + কনটেক্সট-সেফ হিস্ট্রি) | |
| # ======================== | |
| MAX_TURNS = 4 # সীমিত RAM/ctx-তে পুরো history না রেখে শেষ কয়েক টার্ন রাখাই ভালো | |
| def build_prompt(message, history): | |
| trimmed = history[-MAX_TURNS:] if history else [] | |
| prompt = "" | |
| for item in trimmed: | |
| if isinstance(item, (list, tuple)) and len(item) >= 2: | |
| user_msg, bot_msg = item[0], item[1] | |
| # আগের রেসপন্স থেকে স্পিড-মেট্রিক অংশ বাদ দিন যাতে prompt নোংরা না হয় | |
| if bot_msg: | |
| bot_msg = bot_msg.split("\n\n⚡")[0] | |
| prompt += f"User: {user_msg}\nAssistant: {bot_msg}\n" | |
| prompt += f"User: {message}\nAssistant:" | |
| return prompt | |
| def generate_response(message, history): | |
| prompt = build_prompt(message, history) | |
| start_time = time.time() | |
| try: | |
| stream = llm( | |
| prompt, | |
| max_tokens=200, # সামান্য কমানো — লেটেন্সি cap | |
| stop=["User:", "\nUser"], | |
| echo=False, | |
| stream=True, | |
| temperature=0.2, | |
| top_p=0.9, | |
| repeat_penalty=1.15, | |
| ) | |
| except Exception as e: | |
| yield f"⚠️ ত্রুটি হয়েছে: {e}" | |
| return | |
| response_text = "" | |
| token_count = 0 | |
| UI_UPDATE_EVERY = 3 # প্রতি টোকেনে UI re-render না করে ৩ টোকেন পরপর আপডেট — actual generation-এ বেশি CPU সময় যায় | |
| try: | |
| for chunk in stream: | |
| choices = chunk.get("choices", []) | |
| if choices: | |
| delta = choices[0].get("text", "") | |
| if delta: | |
| response_text += delta | |
| token_count += 1 | |
| if token_count % UI_UPDATE_EVERY == 0: | |
| yield response_text + "▌" | |
| except Exception as e: | |
| yield response_text + f"\n\n⚠️ স্ট্রিমিং-এ সমস্যা: {e}" | |
| return | |
| elapsed = time.time() - start_time | |
| speed = token_count / elapsed if elapsed > 0 else 0 | |
| yield f"{response_text}\n\n⚡ {speed:.1f} tok/s | {elapsed:.1f}s" | |
| # ======================== | |
| # ৪. Gradio UI | |
| # ======================== | |
| with gr.Blocks(title="Bonsai-8B (CPU)", theme=gr.themes.Soft()) as demo: | |
| gr.Markdown(""" | |
| # 🌳 Bonsai-8B Chat | |
| ### ⚡ ২-কোর CPU | ১৬ GB RAM | ১-বিট কোয়ান্টাইজড | স্ট্রিমিং | |
| """) | |
| gr.ChatInterface( | |
| fn=generate_response, | |
| title="Bonsai-8B", | |
| description="আপনার প্রশ্ন করুন... (টাইপিং ইফেক্ট দেখতে পাবেন)", | |
| concurrency_limit=1, # ২ vCPU-তে একসাথে একাধিক জেনারেশন চালালে দুটোই স্লো হয়ে যায়; একবারে একটাই প্রসেস হবে | |
| ) | |
| if __name__ == "__main__": | |
| demo.queue().launch(server_name="0.0.0.0", server_port=7860) | |