""" GeoLLM Demo — Mineral Exploration Geology Assistant Gradio chat interface for GeoLLM-Qwen3.5-0.8B running on CPU with transformers. Designed for HuggingFace Spaces free tier (2 vCPUs, 16 GB RAM). """ import threading import gradio as gr import torch from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer # --------------------------------------------------------------------------- # Configuration # --------------------------------------------------------------------------- MODEL_ID = "AshkanTaghipour/GeoLLM-Qwen3.5-0.8B" SYSTEM_PROMPT = ( "You are a specialist geologist and exploration consultant with over " "10 years of experience in Western Australian and Queensland mineral " "exploration. You provide expert advice on geological interpretation, " "exploration methods, deposit models, geochemistry, geophysics, and " "drilling strategies. You answer like a knowledgeable colleague — concise, " "technically specific, and grounded in real geological data." ) EXAMPLES = [ "What geophysical methods target komatiite-hosted nickel sulphides in the Eastern Goldfields?", "What are the key pathfinder elements for orogenic gold in the Yilgarn Craton?", "How would you design a soil geochemistry survey for lithium pegmatite exploration?", "What structural controls are important for VMS base metal deposits?", "Explain the difference between IOCG and orogenic gold deposit models.", ] # --------------------------------------------------------------------------- # Model loading # --------------------------------------------------------------------------- print(f"Loading {MODEL_ID} ...") tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True) model = AutoModelForCausalLM.from_pretrained( MODEL_ID, torch_dtype=torch.float32, device_map="cpu", trust_remote_code=True, ) model.eval() print("Model ready.") # --------------------------------------------------------------------------- # Inference # --------------------------------------------------------------------------- def respond(message, chat_history): """Stream a response for a geology question.""" if not message.strip(): yield "", chat_history return messages = [{"role": "system", "content": SYSTEM_PROMPT}] for user_msg, assistant_msg in chat_history: messages.append({"role": "user", "content": user_msg}) if assistant_msg: messages.append({"role": "assistant", "content": assistant_msg}) messages.append({"role": "user", "content": message}) text = tokenizer.apply_chat_template( messages, tokenize=False, add_generation_prompt=True, enable_thinking=False, ) inputs = tokenizer(text, return_tensors="pt").to(model.device) streamer = TextIteratorStreamer( tokenizer, skip_prompt=True, skip_special_tokens=True, ) generate_kwargs = dict( **inputs, max_new_tokens=512, temperature=0.6, top_p=0.95, do_sample=True, streamer=streamer, ) thread = threading.Thread(target=model.generate, kwargs=generate_kwargs) thread.start() chat_history = chat_history + [[message, ""]] for new_text in streamer: chat_history[-1][1] += new_text yield "", chat_history thread.join() # --------------------------------------------------------------------------- # Gradio UI # --------------------------------------------------------------------------- theme = gr.themes.Soft( font=gr.themes.GoogleFont("Sora"), font_mono=gr.themes.GoogleFont("JetBrains Mono"), ) with gr.Blocks(theme=theme, title="GeoLLM") as demo: # --- Header --- gr.Markdown( "# \u26cf\ufe0f GeoLLM — Mineral Exploration Geology Assistant" ) # --- Intro + Map side by side --- with gr.Row(): with gr.Column(scale=3): gr.Markdown( "\U0001f30f **Domain-adapted LLM for mineral exploration geology.**\n\n" "Ask questions about deposit models, geochemistry, geophysics, " "drilling strategies, and regional geology — the model answers " "like a knowledgeable colleague.\n\n" "\U0001f4da Trained on **479 expert QA pairs** from " "~300 Western Australian exploration reports " "([WAMEX](https://www.dmp.wa.gov.au/WAMEX-Minerals-Exploration-1476.aspx)).\n\n" "\U0001f9e0 **Model:** " "[GeoLLM-Qwen3.5-0.8B](https://huggingface.co/AshkanTaghipour/GeoLLM-Qwen3.5-0.8B) " "(0.8B params) |\u00a0 " "\U0001f4bb **Code:** " "[GitHub](https://github.com/AshkanTaghipour/GeoLLM-Qwen3.5-FineTune) |\u00a0 " "\U0001f4e6 **Dataset:** " "[HuggingFace](https://huggingface.co/datasets/AshkanTaghipour/mineral-exploration-geology-qa)\n\n" "\u23f3 *Running on free CPU — responses may take 30\u201360 seconds.*" ) with gr.Column(scale=1, min_width=200): gr.Image( value="wa_mining_map.jpg", show_label=False, show_download_button=False, show_share_button=False, container=False, height=220, ) gr.Markdown( "