minimal change

This commit is contained in:
2025-08-03 06:52:55 +00:00
parent 630a2bf913
commit 2a15a4052e
8 changed files with 23 additions and 32 deletions

6
.gitignore vendored
View File

@@ -1,8 +1,8 @@
/app/.gradio /app/.gradio
/app/core /app/core
/app/shop_chroma_db /app/data/chroma_db
/app/amvera_data/chroma_db /app/data/parsed_json/
/app/amvera_data/parsed_json/ /app/data/docs/
/app/__pycache__ /app/__pycache__
/models /models
/cache /cache

View File

@@ -6,14 +6,14 @@ from pydantic_settings import BaseSettings, SettingsConfigDict
class Config(BaseSettings): class Config(BaseSettings):
BASE_DIR: str = os.path.abspath(os.path.join(os.path.dirname(__file__))) BASE_DIR: str = os.path.abspath(os.path.join(os.path.dirname(__file__)))
DOCS_AMVERA_PATH: str = os.path.join(BASE_DIR, "amvera_data", "docs_amvera") DOCS_PATH: str = os.path.join(BASE_DIR, "data", "docs")
PARSED_JSON_PATH: str = os.path.join(BASE_DIR, "amvera_data", "parsed_json") PARSED_JSON_PATH: str = os.path.join(BASE_DIR, "data", "parsed_json")
AMVERA_CHROMA_PATH: str = os.path.join(BASE_DIR, "amvera_data", "chroma_db") DOCS_CHROMA_PATH: str = os.path.join(BASE_DIR, "data", "chroma_db")
AMVERA_COLLECTION_NAME: str = "amvera_docs" DOCS_COLLECTION_NAME: str = "docs"
MAX_CHUNK_SIZE: int = 512 MAX_CHUNK_SIZE: int = 512
CHUNK_OVERLAP: int = 50 CHUNK_OVERLAP: int = 50
LM_MODEL_NAME: str = "/models/paraphrase-multilingual-MiniLM-L12-v2" LM_MODEL_NAME: str = "/models/paraphrase-multilingual-MiniLM-L12-v2"
LOCAL_LLM_NAME: str = "/models/Qwen3-4B-Base" LOCAL_LLM_NAME: str = "/models/Qwen3-4B"
QWEN_MODEL_NAME: str = "qwen3-chat" QWEN_MODEL_NAME: str = "qwen3-chat"

View File

@@ -112,7 +112,7 @@ def process_all_markdown(input_folder: str, output_folder: str) -> None:
if __name__ == "__main__": if __name__ == "__main__":
try: try:
process_all_markdown( process_all_markdown(
input_folder=settings.DOCS_AMVERA_PATH, input_folder=settings.DOCS_PATH,
output_folder=settings.PARSED_JSON_PATH, output_folder=settings.PARSED_JSON_PATH,
) )
except Exception as e: except Exception as e:

View File

@@ -60,7 +60,7 @@ def generate_chroma_db() -> Optional[Chroma]:
"""Инициализация ChromaDB с данными из JSON файлов.""" """Инициализация ChromaDB с данными из JSON файлов."""
try: try:
# Создаем директорию для хранения базы данных, если она не существует # Создаем директорию для хранения базы данных, если она не существует
os.makedirs(settings.AMVERA_CHROMA_PATH, exist_ok=True) os.makedirs(settings.DOCS_CHROMA_PATH, exist_ok=True)
# Загружаем JSON файлы # Загружаем JSON файлы
documents = load_json_files(settings.PARSED_JSON_PATH) documents = load_json_files(settings.PARSED_JSON_PATH)
@@ -95,8 +95,8 @@ def generate_chroma_db() -> Optional[Chroma]:
embedding=embeddings, embedding=embeddings,
ids=ids, ids=ids,
metadatas=metadatas, metadatas=metadatas,
persist_directory=settings.AMVERA_CHROMA_PATH, persist_directory=settings.DOCS_CHROMA_PATH,
collection_name=settings.AMVERA_COLLECTION_NAME, collection_name=settings.DOCS_COLLECTION_NAME,
collection_metadata={ collection_metadata={
"hnsw:space": "cosine", "hnsw:space": "cosine",
}, },

View File

@@ -4,7 +4,7 @@ import torch
import threading import threading
# Пути к модели # Пути к модели
model_name = "/models/Qwen3-4B-Base" model_name = "/models/Qwen3-8B"
# Загрузка токенизатора и модели (один раз при старте) # Загрузка токенизатора и модели (один раз при старте)
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True) tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)

View File

@@ -18,17 +18,17 @@ class ChatWithAI:
) )
if provider == "qwen3": if provider == "qwen3":
model_name = getattr(settings, "LOCAL_LLM_NAME", "/models/Qwen3-4B-Base") model_name = getattr(settings, "LOCAL_LLM_NAME", "/models/Qwen3-4B")
logger.info(f"Загрузка локальной модели: {model_name}") logger.info(f"Загрузка локальной модели: {model_name}")
tokenizer = AutoTokenizer.from_pretrained(model_name) tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained( model = AutoModelForCausalLM.from_pretrained(
model_name, model_name,
torch_dtype=torch.float16, torch_dtype=torch.float32,
device_map="cuda", device_map="cuda",
) )
# Создаём text-generation pipeline #Создаём text-generation pipeline
self.llm = pipeline( self.llm = pipeline(
"text-generation", "text-generation",
model=model, model=model,
@@ -43,9 +43,9 @@ class ChatWithAI:
raise ValueError(f"Неподдерживаемый провайдер: {provider}") raise ValueError(f"Неподдерживаемый провайдер: {provider}")
self.chroma_db = Chroma( self.chroma_db = Chroma(
persist_directory=settings.AMVERA_CHROMA_PATH, persist_directory=settings.DOCS_CHROMA_PATH,
embedding_function=self.embeddings, embedding_function=self.embeddings,
collection_name=settings.AMVERA_COLLECTION_NAME, collection_name=settings.DOCS_COLLECTION_NAME,
) )
def get_relevant_context(self, query: str, k: int = 3) -> List[Dict[str, Any]]: def get_relevant_context(self, query: str, k: int = 3) -> List[Dict[str, Any]]:
@@ -89,13 +89,13 @@ class ChatWithAI:
Правила: Правила:
1. Сразу переходи к сути, без фраз типа "На основе контекста" 1. Сразу переходи к сути, без фраз типа "На основе контекста"
2. Используй только факты. Если точных данных нет — отвечай общими фразами об Amvera Cloud, но не придумывай конкретику 2. Используй только факты. Если точных данных нет — отвечай общими фразами об Marzban, но не придумывай конкретику
3. Используй обычный текст без форматирования 3. Используй обычный текст без форматирования
4. Включай ссылки только если они есть в контексте 4. Включай ссылки только если они есть в контексте
5. Говори от первого лица множественного числа: "Мы предоставляем", "У нас есть" 5. Говори от первого лица множественного числа: "Мы предоставляем", "У нас есть"
6. При упоминании файлов делай это естественно, например: "Я прикреплю инструкцию, где подробно описаны шаги" 6. При упоминании файлов делай это естественно, например: "Я прикреплю инструкцию, где подробно описаны шаги"
7. На приветствия отвечай доброжелательно, на негатив — с легким юмором 7. На приветствия отвечай доброжелательно, на негатив — с легким юмором
8. Можешь при ответах использовать общую информацию из открытых источников по Amvera Cloud, но опирайся на контекст 8. Можешь при ответах использовать общую информацию из открытых источников по Marzban, но опирайся на контекст
9. Если пользователь спрашивает о ценах, планах или технических характеристиках — давай конкретные ответы из контекста 9. Если пользователь спрашивает о ценах, планах или технических характеристиках — давай конкретные ответы из контекста
10. При технических вопросах предлагай практические решения 10. При технических вопросах предлагай практические решения
@@ -114,7 +114,7 @@ class ChatWithAI:
# Применяем chat template (поддерживается в современных моделях: Zephyr, Llama3, Qwen и т.д.) # Применяем chat template (поддерживается в современных моделях: Zephyr, Llama3, Qwen и т.д.)
prompt = tokenizer.apply_chat_template( prompt = tokenizer.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True messages, tokenize=False, add_generation_prompt=True, enable_thinking=False
) )
# Генерация # Генерация

View File

@@ -2,7 +2,8 @@
transformers>=4.50.0 transformers>=4.50.0
gradio>=4.29.0 gradio>=4.29.0
safetensors>=0.4.3 safetensors>=0.4.3
accelerate>=1.9.0 accelerate==1.9.0
psutil==7.0.0
langchain-huggingface==0.1.2 langchain-huggingface==0.1.2
torch>=2.7.1 torch>=2.7.1
loguru==0.7.3 loguru==0.7.3

View File

@@ -1,10 +0,0 @@
langchain-huggingface==0.1.2
torch>=2.7.1
loguru==0.7.3
chromadb==0.6.3
sentence-transformers==3.4.1
langchain-chroma==0.2.2
pydantic-settings==2.8.1
langchain-text-splitters==0.3.7
langchain-qwen3==0.1.0
langchain-openai==0.3.11