Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import requests | |
| import os | |
| from transformers import AutoModelForCausalLM, AutoTokenizer | |
| import torch | |
| # ========== 从环境变量读取密钥 ========== | |
| OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY") | |
| CEREBRAS_API_KEY = os.getenv("CEREBRAS_API_KEY") | |
| # ========== 模型定义 ========== | |
| LOCAL_MODELS = { | |
| "DistilGPT2 (最快)": "distilgpt2", | |
| "DialoGPT-small (轻量)": "microsoft/DialoGPT-small", | |
| "DialoGPT-medium (均衡)": "microsoft/DialoGPT-medium", | |
| } | |
| OPENROUTER_MODELS = { | |
| "Llama 3.3 70B (免费)": "meta-llama/llama-3.3-70b-instruct:free", | |
| "Nemotron 3 Super (免费)": "nvidia/nemotron-3-super:free", | |
| "Qwen3 Next 80B (免费)": "qwen/qwen3-next-80b:free", | |
| } | |
| CEREBRAS_MODELS = { | |
| "Llama 3.1 8B (Cerebras)": "llama3.1-8b", | |
| } | |
| local_model_cache = {} | |
| def load_local_model(model_key): | |
| if model_key in local_model_cache: | |
| return local_model_cache[model_key] | |
| model_id = LOCAL_MODELS[model_key] | |
| tokenizer = AutoTokenizer.from_pretrained(model_id) | |
| model = AutoModelForCausalLM.from_pretrained(model_id) | |
| if tokenizer.pad_token is None: | |
| tokenizer.pad_token = tokenizer.eos_token | |
| local_model_cache[model_key] = (model, tokenizer) | |
| return model, tokenizer | |
| def is_chinese(text): | |
| return any('\u4e00' <= c <= '\u9fff' for c in text) | |
| def local_predict(message, model_key): | |
| if is_chinese(message): | |
| return "⚠️ This model only supports English input. 请使用英文。" | |
| model, tokenizer = load_local_model(model_key) | |
| inputs = tokenizer.encode(message + tokenizer.eos_token, return_tensors='pt') | |
| outputs = model.generate( | |
| inputs, | |
| max_new_tokens=100, | |
| do_sample=True, | |
| temperature=0.7, | |
| repetition_penalty=1.2, | |
| pad_token_id=tokenizer.eos_token_id | |
| ) | |
| reply = tokenizer.decode(outputs[0][inputs.shape[-1]:], skip_special_tokens=True) | |
| return reply.strip() or "I'm not sure how to respond." | |
| def openrouter_predict(message, model_name): | |
| if not OPENROUTER_API_KEY: | |
| return "❌ OpenRouter API key 未设置,请在 Space Secrets 中添加 OPENROUTER_API_KEY" | |
| headers = { | |
| "Authorization": f"Bearer {OPENROUTER_API_KEY}", | |
| "HTTP-Referer": "https://your-space.hf.space", | |
| "X-Title": "AI ChatBot", | |
| "Content-Type": "application/json" | |
| } | |
| payload = { | |
| "model": model_name, | |
| "messages": [{"role": "user", "content": message}], | |
| "max_tokens": 500, | |
| "temperature": 0.7 | |
| } | |
| try: | |
| resp = requests.post("https://openrouter.ai/api/v1/chat/completions", headers=headers, json=payload, timeout=60) | |
| if resp.status_code == 200: | |
| return resp.json()["choices"][0]["message"]["content"] | |
| elif resp.status_code == 402: | |
| return "⚠️ 免费额度已用完或需启用付费模型。" | |
| else: | |
| return f"❌ API 错误 {resp.status_code}" | |
| except Exception as e: | |
| return f"❌ 请求失败: {e}" | |
| def cerebras_predict(message, model_name): | |
| if not CEREBRAS_API_KEY: | |
| return "❌ Cerebras API key 未设置,请在 Space Secrets 中添加 CEREBRAS_API_KEY" | |
| headers = { | |
| "Authorization": f"Bearer {CEREBRAS_API_KEY}", | |
| "Content-Type": "application/json" | |
| } | |
| payload = { | |
| "model": model_name, | |
| "messages": [{"role": "user", "content": message}], | |
| "max_tokens": 500, | |
| "temperature": 0.7 | |
| } | |
| try: | |
| resp = requests.post("https://api.cerebras.ai/v1/chat/completions", headers=headers, json=payload, timeout=60) | |
| if resp.status_code == 200: | |
| return resp.json()["choices"][0]["message"]["content"] | |
| else: | |
| return f"❌ Cerebras 错误 {resp.status_code}" | |
| except Exception as e: | |
| return f"❌ 请求失败: {e}" | |
| def predict(message, history, backend, model_choice): | |
| if not message.strip(): | |
| return "" | |
| if backend == "本地 CPU 模型 (限英文)": | |
| return local_predict(message, model_choice) | |
| elif backend == "OpenRouter (不限语言)": | |
| return openrouter_predict(message, model_choice) | |
| elif backend == "Cerebras (不限语言)": | |
| return cerebras_predict(message, model_choice) | |
| else: | |
| return "未知后端" | |
| with gr.Blocks(title="多后端 AI 聊天机器人", theme=gr.themes.Soft()) as demo: | |
| gr.Markdown("# 🧠 多后端 AI 聊天机器人") | |
| gr.Markdown("**本地 CPU 模型**仅限英文;**OpenRouter / Cerebras** 不限语言,且质量更高。") | |
| with gr.Row(): | |
| backend_radio = gr.Radio( | |
| choices=["本地 CPU 模型 (限英文)", "OpenRouter (不限语言)", "Cerebras (不限语言)"], | |
| label="选择后端", | |
| value="本地 CPU 模型 (限英文)" | |
| ) | |
| model_dropdown = gr.Dropdown( | |
| choices=list(LOCAL_MODELS.keys()), | |
| label="模型选择", | |
| value=list(LOCAL_MODELS.keys())[2] | |
| ) | |
| def update_model_dropdown(backend): | |
| if backend == "本地 CPU 模型 (限英文)": | |
| return gr.update(choices=list(LOCAL_MODELS.keys()), value=list(LOCAL_MODELS.keys())[2], visible=True) | |
| elif backend == "OpenRouter (不限语言)": | |
| return gr.update(choices=list(OPENROUTER_MODELS.keys()), value=list(OPENROUTER_MODELS.keys())[0], visible=True) | |
| else: | |
| return gr.update(choices=list(CEREBRAS_MODELS.keys()), value=list(CEREBRAS_MODELS.keys())[0], visible=True) | |
| backend_radio.change(fn=update_model_dropdown, inputs=backend_radio, outputs=model_dropdown) | |
| chatbot = gr.ChatInterface( | |
| fn=predict, | |
| additional_inputs=[backend_radio, model_dropdown], | |
| title=None, | |
| description="多轮对话,自动记忆上下文。" | |
| ) | |
| demo.launch(server_port=7860) |