Spaces:
Runtime error
Runtime error
File size: 12,930 Bytes
6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd 3eaaefb 6925fdd 3eaaefb 2824061 3eaaefb 2824061 3eaaefb 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 2824061 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd adbdeb6 6925fdd 3eaaefb |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
import gradio as gr
import os
import re
# Конфигурация модели
MODEL_NAME = "Qwen/Qwen2.5-Coder-14B-Instruct-GPTQ-Int4"
DEVICE = "cpu" # Запуск на CPU
# Глобальная загрузка модели (один раз при запуске)
def load_model():
print("🔄 Загружаем токенизатор...")
tokenizer = AutoTokenizer.from_pretrained(
MODEL_NAME,
trust_remote_code=True
)
# Добавляем pad token если его нет
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
print("🔄 Загружаем GPTQ-модель Qwen2.5-Coder-14B...")
model = AutoModelForCausalLM.from_pretrained(
MODEL_NAME,
torch_dtype=torch.float32, # Используем float32 для CPU
device_map="cpu", # Явно указываем CPU
trust_remote_code=True
)
model.eval() # Переводим модель в режим оценки
return tokenizer, model
# Загружаем модель один раз при старте
try:
tokenizer, model = load_model()
print("✅ Qwen2.5-Coder-14B-Instruct-GPTQ-Int4 успешно загружена!")
except Exception as e:
print(f"❌ Ошибка загрузки модели: {e}")
tokenizer, model = None, None
def read_file_content(file_path):
"""Читает содержимое файла с обработкой различных кодировок"""
try:
# Пробуем разные кодировки
encodings = ['utf-8', 'cp1251', 'iso-8859-1', 'windows-1251']
for encoding in encodings:
try:
with open(file_path, 'r', encoding=encoding) as f:
content = f.read()
return content
except UnicodeDecodeError:
continue
# Если текстовые кодировки не работают, пробуем бинарный режим
if file_path.endswith(('.py', '.txt', '.js', '.html', '.css', '.json', '.md')):
with open(file_path, 'rb') as f:
content = f.read()
return content.decode('utf-8', errors='replace')
else:
return f"Файл {os.path.basename(file_path)} не является текстовым файлом"
except Exception as e:
return f"Ошибка чтения файла: {str(e)}"
def extract_search_terms(prompt):
"""Извлекает поисковые термины из промпта в формате [поиск: ...]"""
search_pattern = r'\[поиск:\s*(.*?)\]'
matches = re.findall(search_pattern, prompt, re.IGNORECASE)
if matches:
# Удаляем поисковую часть из промпта
clean_prompt = re.sub(search_pattern, '', prompt).strip()
return clean_prompt, matches[0].strip()
return prompt, None
def generate_code_with_context(prompt, files, max_length=1024, temperature=0.7, top_p=0.9):
"""
Генерирует код на основе промпта пользователя с учетом загруженных файлов.
Эта функция автоматически станет доступна как MCP-инструмент для других приложений.
Args:
prompt (str): Запрос пользователя, может содержать [поиск: термин]
files (list): Список загруженных файлов для анализа
max_length (int): Максимальная длина ответа в токенах
temperature (float): Параметр температуры для генерации
top_p (float): Параметр top-p для генерации
Returns:
str: Сгенерированный код или сообщение об ошибке
"""
if model is None or tokenizer is None:
return "❌ Ошибка: модель не загружена. Проверьте:\n- Подключение к интернету\n- Достаточно ли оперативной памяти (рекомендуется 16+ ГБ)\n- Установлены ли зависимости: `pip install auto-gptq optimum`"
try:
# Извлекаем поисковые термины из промпта
clean_prompt, search_term = extract_search_terms(prompt)
# Обрабатываем загруженные файлы
file_contexts = []
if files:
for file_info in files:
if hasattr(file_info, 'name'):
file_path = file_info.name
else:
file_path = file_info
content = read_file_content(file_path)
filename = os.path.basename(file_path)
file_contexts.append(f"Файл: {filename}\n```\n{content[:2000]}\n```")
# Формируем финальный промпт
final_prompt = clean_prompt
if file_contexts:
files_context = "\n\n".join(file_contexts)
final_prompt = f"""Контекст из загруженных файлов:
{files_context}
Запрос: {clean_prompt}"""
# Форматируем сообщение для модели в соответствии с официальным форматом Qwen2.5 :cite[1]
messages = [
{"role": "system", "content": "You are Qwen, created by Alibaba Cloud. You are a helpful assistant."},
{"role": "user", "content": final_prompt}
]
# Применяем шаблон чата :cite[1]
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
# Токенизируем входные данные с ограничением длины
inputs = tokenizer(
text,
return_tensors="pt",
truncation=True,
max_length=2048,
padding=True,
return_attention_mask=True
)
# Генерация с использованием обновленного кода и attention_mask
with torch.no_grad():
generated_ids = model.generate(
inputs.input_ids,
attention_mask=inputs.attention_mask, # Добавляем attention_mask
max_new_tokens=max_length,
temperature=temperature,
top_p=top_p,
do_sample=True,
pad_token_id=tokenizer.eos_token_id,
repetition_penalty=1.1,
no_repeat_ngram_size=3
)
# Декодируем результат
generated_text = tokenizer.decode(generated_ids[0], skip_special_tokens=True)
# Убираем оригинальный промпт из ответа
if generated_text.startswith(text):
response = generated_text[len(text):].strip()
else:
response = generated_text.strip()
return response
except Exception as e:
return f"❌ Ошибка при генерации кода: {str(e)}"
# Создаем интерфейс Gradio
with gr.Blocks(title="Qwen2.5-Coder-14B with MCP", theme=gr.themes.Soft()) as demo:
gr.Markdown("""
# 🚀 Qwen2.5-Coder-14B-Instruct-GPTQ-Int4 + MCP
**Профессиональный генератор кода с поддержкой Model Context Protocol**
""")
with gr.Row():
with gr.Column():
prompt_input = gr.Textbox(
lines=4,
placeholder="""Введите ваш запрос... Примеры:
- "Напиши функцию для быстрой сортировки на Python"
- "Создай REST API на FastAPI для управления пользователями"
- "Найди и исправь ошибку в загруженном коде [поиск: syntax error]" """,
label="Запрос на генерацию кода",
info="Используйте [поиск: ...] для поиска в файлах"
)
with gr.Accordion("📁 Загрузка файлов для анализа", open=True):
file_input = gr.File(
label="Загрузите файлы для анализа",
file_count="multiple",
file_types=[".txt", ".py", ".js", ".html", ".css", ".json", ".md", ".java", ".cpp", ".c"],
type="filepath"
)
with gr.Accordion("⚙️ Параметры генерации", open=False):
max_length_slider = gr.Slider(
minimum=100, maximum=2048, value=512,
label="Максимальная длина ответа (токены)"
)
temperature_slider = gr.Slider(
minimum=0.1, maximum=1.0, value=0.7,
label="Температура (креативность)"
)
top_p_slider = gr.Slider(
minimum=0.1, maximum=1.0, value=0.9,
label="Top-p (вероятностный отбор)"
)
generate_btn = gr.Button("🚀 Сгенерировать код", variant="primary")
with gr.Column():
response_output = gr.Textbox(
label="Сгенерированный код",
lines=18,
show_copy_button=True
)
# Добавляем информацию о MCP
with gr.Accordion("🔗 MCP Сервер - Подключение к другим приложениям", open=True):
gr.Markdown("""
**MCP (Model Context Protocol) сервер активирован!**
Ваш генератор кода теперь доступен как MCP-инструмент для:
- Claude Desktop
- Cursor
- Cline
- Других MCP-клиентов
**URL для подключения:**
- Основной MCP URL: `http://localhost:7860/gradio_api/mcp/`
- SSE URL: `http://localhost:7860/gradio_api/mcp/sse`
**Для подключения к Claude Desktop** добавьте в настройки (`claude_desktop_config.json`):
```json
{
"mcpServers": {
"qwen-coder-generator": {
"url": "http://localhost:7860/gradio_api/mcp/sse"
}
}
}
```
""")
# Информация о модели
with gr.Accordion("ℹ️ О модели Qwen2.5-Coder-14B", open=False):
gr.Markdown("""
**Qwen2.5-Coder-14B-Instruct** - это специализированная модель для программирования :cite[6]:
- **Параметры**: 14.7 миллиардов (квантованные в INT4)
- **Специализация**: Генерация кода, исправление ошибок, код-ризонинг
- **Контекст**: До 128K токенов :cite[1]
- **Языки программирования**: Поддержка 40+ языков :cite[6]
- **Память**: ~4-6 ГБ RAM (благодаря GPTQ-квантованию)
**Улучшения Qwen2.5 по сравнению с Qwen2** :cite[1]:
- Значительно больше знаний и улучшенные возможности в программировании
- Улучшенное следование инструкциям и генерация длинных текстов
- Поддержка многоязычия (29+ языков)
""")
# Обработчики событий
generate_btn.click(
fn=generate_code_with_context,
inputs=[prompt_input, file_input, max_length_slider, temperature_slider, top_p_slider],
outputs=response_output
)
# Запускаем приложение с MCP-сервером
if __name__ == "__main__":
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
ssr_mode=False, # Явно отключаем SSR
mcp_server=True
) |