Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import subprocess | |
| import base64 | |
| import os | |
| from huggingface_hub import hf_hub_download | |
| # --- 1. Setup & Install --- | |
| subprocess.run("pip install -q 'llama_cpp_python==0.3.15'", shell=True, check=False) | |
| from llama_cpp import Llama | |
| # --- 2. Load Model (GGUF) --- | |
| MODEL_REPO = "Jeppcode/ScalableLab2" | |
| GGUF_FILENAME = "model-q4_k_m.gguf" | |
| print(f"Downloading GGUF model {MODEL_REPO}/{GGUF_FILENAME} ...") | |
| model_path = hf_hub_download( | |
| repo_id=MODEL_REPO, | |
| filename=GGUF_FILENAME, | |
| ) | |
| print("Initializing llama.cpp LLM ...") | |
| llm = Llama( | |
| model_path=model_path, | |
| n_ctx=2048, | |
| n_threads=2, | |
| n_batch=64, | |
| use_mmap=True, | |
| use_mlock=False, | |
| ) | |
| # --- 3. Image Handling (The Fix) --- | |
| def encode_image(image_path): | |
| """ | |
| Reads the local image and converts it to a base64 string. | |
| This ensures it loads in the CSS without 404 errors. | |
| """ | |
| if not os.path.exists(image_path): | |
| return "" # Fail silently if file missing | |
| with open(image_path, "rb") as image_file: | |
| encoded_string = base64.b64encode(image_file.read()).decode('utf-8') | |
| return f"data:image/jpeg;base64,{encoded_string}" | |
| # Exact filename from your screenshot | |
| IMG_FILENAME = "Cute-Christmas-Background-edit-online-1.jpg" | |
| bg_image_data = encode_image(IMG_FILENAME) | |
| # --- 4. Prompts & Logic --- | |
| STYLE_SYSTEM_PROMPTS = { | |
| "Default": "You are a helpful, polite assistant.", | |
| "Short answer": "You are a helpful assistant. Answer as concisely as possible, usually in 1–3 sentences.", | |
| "Detailed explanation": "You are a helpful teaching assistant. Give clear, structured and detailed explanations.", | |
| "Step-by-step reasoning": "You are a careful problem solver. Think step by step and explain your reasoning clearly.", | |
| } | |
| def _extract_text(content): | |
| if isinstance(content, list): | |
| return "\n".join( | |
| block.get("text", "") for block in content | |
| if isinstance(block, dict) and block.get("type") == "text" | |
| ) | |
| return str(content) | |
| def build_prompt(message, history, style): | |
| system_prompt = STYLE_SYSTEM_PROMPTS.get(style, STYLE_SYSTEM_PROMPTS["Default"]) | |
| prompt_parts = [f"System: {system_prompt}\n", "Conversation:\n"] | |
| for msg in history or []: | |
| role = msg.get("role") | |
| content = _extract_text(msg.get("content", "")) | |
| if content: | |
| if role == "user": prompt_parts.append(f"User: {content}\n") | |
| elif role == "assistant": prompt_parts.append(f"Assistant: {content}\n") | |
| prompt_parts.append(f"User: {message}\n") | |
| prompt_parts.append("Assistant:") | |
| return "".join(prompt_parts) | |
| def chat_fn(message, history, max_new_tokens, style): | |
| temperature = 0.7 | |
| top_p = 0.9 | |
| repetition_penalty = 1.1 | |
| prompt = build_prompt(message, history, style) | |
| output = llm( | |
| prompt, | |
| max_tokens=int(max_new_tokens), | |
| temperature=temperature, | |
| top_p=top_p, | |
| repeat_penalty=repetition_penalty, | |
| stop=["User:", "Assistant:", "System:", "Conversation:"], | |
| ) | |
| return output["choices"][0]["text"].strip() | |
| # --- 5. Theme & CSS --- | |
| winter_theme = gr.themes.Soft( | |
| primary_hue="blue", | |
| neutral_hue="slate", | |
| ).set( | |
| body_background_fill="transparent", | |
| block_background_fill="rgba(10, 20, 40, 0.7)", | |
| border_color_primary="#FFFFFF", | |
| button_primary_background_fill="#FFFFFF", | |
| button_primary_text_color="#000000", | |
| ) | |
| # We inject the base64 image data directly into the URL() | |
| custom_css = f""" | |
| /* Apply Background to the main app container */ | |
| .gradio-container {{ | |
| background-image: url('{bg_image_data}') !important; | |
| background-size: cover !important; | |
| background-position: center center !important; | |
| background-attachment: fixed !important; | |
| background-repeat: no-repeat !important; | |
| }} | |
| /* Ensure the main content area is transparent so bg shows */ | |
| .gradio-container > .main {{ | |
| background: transparent !important; | |
| }} | |
| /* Dark Glassy Look for Chat and Settings */ | |
| .group, .form, .bubble-wrap {{ | |
| background: rgba(15, 23, 42, 0.75) !important; | |
| border: 2px solid #FFFFFF !important; | |
| border-radius: 12px !important; | |
| backdrop-filter: blur(4px); | |
| box-shadow: 0 4px 15px rgba(0,0,0,0.5); | |
| }} | |
| /* Chat Bubbles */ | |
| .user-message {{ | |
| background-color: rgba(255, 255, 255, 0.2) !important; | |
| border: 1px solid #FFFFFF !important; | |
| color: #FFFFFF !important; | |
| }} | |
| .bot-message {{ | |
| background-color: rgba(0, 0, 0, 0.6) !important; | |
| border: 1px solid #A0A0A0 !important; | |
| color: #E0E0E0 !important; | |
| }} | |
| /* Inputs and Text */ | |
| textarea, input {{ | |
| background-color: rgba(0, 0, 0, 0.5) !important; | |
| border: 1px solid #FFFFFF !important; | |
| color: white !important; | |
| }} | |
| label, span, p, .prose {{ | |
| color: #FFFFFF !important; | |
| text-shadow: 1px 1px 2px black; | |
| }} | |
| footer {{visibility: hidden}} | |
| """ | |
| max_new_tokens_slider = gr.Slider( | |
| minimum=16, maximum=256, value=64, step=8, label="Max Response Length", | |
| ) | |
| style_radio = gr.Radio( | |
| choices=["Default", "Short answer", "Detailed explanation"], | |
| value="Detailed explanation", | |
| label="Answer style", | |
| ) | |
| # Instantiate | |
| demo = gr.ChatInterface( | |
| fn=chat_fn, | |
| title="❄️ WinterChat Lab 2 ❄️", | |
| description="Stay frosty. Chat with the fine-tuned model.", | |
| additional_inputs=[max_new_tokens_slider, style_radio], | |
| additional_inputs_accordion="Settings", | |
| ) | |
| # Apply configuration | |
| demo.theme = winter_theme | |
| demo.css = custom_css | |
| if __name__ == "__main__": | |
| # allowed_paths=["."] is a backup, but base64 should solve it. | |
| demo.launch(allowed_paths=["."]) |