From 9ad43bcea77d739dbd8e0f8e1d2aef3ecbb3f39e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E9=9B=A8?= Date: Tue, 3 Jun 2025 17:20:18 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9B=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.gitignore | 8 ++ db.sqlite3 | 0 env.sh | 22 +++++ manage.py | 22 +++++ yj_room_agent/LLM/__init__.py | 17 ++++ yj_room_agent/LLM/modelclient.py | 142 +++++++++++++++++++++++++++++++ yj_room_agent/__init__.py | 0 yj_room_agent/asgi.py | 16 ++++ yj_room_agent/settings.py | 117 +++++++++++++++++++++++++ yj_room_agent/urls.py | 24 ++++++ yj_room_agent/views.py | 5 ++ yj_room_agent/wsgi.py | 16 ++++ 12 files changed, 389 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 db.sqlite3 create mode 100644 env.sh create mode 100644 manage.py create mode 100644 yj_room_agent/LLM/__init__.py create mode 100644 yj_room_agent/LLM/modelclient.py create mode 100644 yj_room_agent/__init__.py create mode 100644 yj_room_agent/asgi.py create mode 100644 yj_room_agent/settings.py create mode 100644 yj_room_agent/urls.py create mode 100644 yj_room_agent/views.py create mode 100644 yj_room_agent/wsgi.py diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/db.sqlite3 b/db.sqlite3 new file mode 100644 index 0000000..e69de29 diff --git a/env.sh b/env.sh new file mode 100644 index 0000000..e20f635 --- /dev/null +++ b/env.sh @@ -0,0 +1,22 @@ +REDIS_HOST=10.254.26.176 +REDIS_PORT=16379 +REDIS_PASSWORD=your_password +DEEPSEEK_API_KEY=NotRequiredSinceWeAreLocal +DEEPSEEK_BASE_URL=https://api.deepseek.com +MODEL_NAME=deepseek-chat + + + +PYTHONUNBUFFERED=1;API_KEY=sk-9nng4v6qsdiw42r6d3re4nym15hiti29;BIG_CHAPTER_SIZE=-1;MODEL=deepseek;OPENAI_API_ENDPOINT=https://gateout.yced.com.cn/v1;TASK_CHUNK_SIZE=5;MODEL_NAME=deepseek-chat;MODEL_API_KEY=sk-9nng4v6qsdiw42r6d3re4nym15hiti29;MODEL_BASE_URL=https://gateout.yced.com.cn/v1 + +PYTHONUNBUFFERED=1;API_KEY=sk-e142b47120d145848def68673861dfff;BIG_CHAPTER_SIZE=-1;MODEL=deepseek;OPENAI_API_ENDPOINT=https://api.deepseek.com;TASK_CHUNK_SIZE=5;MODEL_NAME=deepseek-chat;MODEL_API_KEY=sk-e142b47120d145848def68673861dfff;MODEL_BASE_URL=https://api.deepseek.com + + +sk-e142b47120d145848def68673861dfff + + +MINIO_ENDPOINT=10.254.26.176:19000 +MINIO_ACCESS_KEY=root +MINIO_SECRET_KEY=WWw1236912369@ + +MYSQL_HOST=10.254.26.176 diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..39998f5 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'yj_room_agent.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/yj_room_agent/LLM/__init__.py b/yj_room_agent/LLM/__init__.py new file mode 100644 index 0000000..6bdd251 --- /dev/null +++ b/yj_room_agent/LLM/__init__.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +@author: yelinfeng +@contact: 1312954526@qq.com +@version: 1.0 +@created: 2025/5/24 10:24 +""" + + +def main(): + pass + + +if __name__ == '__main__': + main() diff --git a/yj_room_agent/LLM/modelclient.py b/yj_room_agent/LLM/modelclient.py new file mode 100644 index 0000000..bd2710d --- /dev/null +++ b/yj_room_agent/LLM/modelclient.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +@author: yelinfeng +@contact: 1312954526@qq.com +@version: 1.0 +@created: 2025/5/22 18:32 +""" + +import requests +import json +import logging +import os +from typing import Dict, List, Optional + +logger = logging.getLogger(__name__) + + +class ModelClient: + """ + A generic model client to interact with various large language models. + Configured via environment variables. + """ + + def __init__( + self, + base_url: Optional[str] = None, + api_key: Optional[str] = None, + headers: Optional[Dict[str, str]] = None, + model_name: Optional[str] = None + ): + """ + Initialize the model client using environment variables or provided parameters. + + Environment Variables: + MODEL_BASE_URL: Base URL of the model API (e.g., http://10.254.23.128:31205/v1) + MODEL_API_KEY: API key (optional) + MODEL_NAME: Model name (e.g., deepseek-chat) + MODEL_HEADERS: JSON string of custom headers (e.g., '{"User-Agent": "Apifox/1.0.0"}') + + Args: + base_url: Base URL (overrides env var) + api_key: API key (overrides env var) + headers: Custom headers (overrides env var) + model_name: Model name (overrides env var) + """ + self.base_url = base_url or os.getenv('MODEL_BASE_URL', 'http://10.254.23.128:31205/v1').rstrip('/') + self.api_key = api_key or os.getenv('MODEL_API_KEY', 'NotRequiredSinceWeAreLocal') + self.model_name = model_name or os.getenv('MODEL_NAME', 'deepseek-chat') + + # 加载 MODEL_HEADERS + headers_env = os.getenv('MODEL_HEADERS', '{}') + try: + self.headers = json.loads(headers_env) + except json.JSONDecodeError: + logger.error(f"Invalid MODEL_HEADERS format: {headers_env}. Using empty headers.") + self.headers = {} + + # 添加默认 headers + self.headers.setdefault('Content-Type', 'application/json') + # if headers: + # self.headers.update(headers) + + # 处理 api_key + if self.api_key and self.api_key != 'NotRequiredSinceWeAreLocal' and 'Authorization' not in self.headers: + self.headers['Authorization'] = f'Bearer {self.api_key}' + + # # 添加默认 User-Agent + self.headers.setdefault('User-Agent', '') + + # 验证配置 + if not self.base_url: + raise ValueError("MODEL_BASE_URL is required") + if not self.model_name: + raise ValueError("MODEL_NAME is required") + + logger.info( + f"Initialized ModelClient: base_url={self.base_url}, model_name={self.model_name}, headers={self.headers}") + + def create(self, messages: List[Dict[str, str]], stream=True): + """ + Send a chat completion request to the model. + + Args: + messages: List of messages [{'role': 'system', 'content': '...'}, ...] + **kwargs: Additional parameters (e.g., temperature, max_tokens) + + Returns: + Dict: Model response + + Raises: + Exception: If the request fails + """ + url = f"{self.base_url}/v1/chat/completions" + payload = { + 'model': self.model_name, + 'messages': messages, + 'stream': stream + } + + try: + with requests.post( + url, + headers=self.headers, + json=payload, + stream=True, + timeout=30 + ) as response: + response.raise_for_status() + + for chunk in response.iter_lines(): + if chunk: + decoded = chunk.decode('utf-8') + if decoded.startswith("data: "): + json_str = decoded[6:] + try: + data = json.loads(json_str) + if "choices" in data: + content = data["choices"][0].get("delta", {}).get("content", "") + if content: + yield content + except json.JSONDecodeError: + continue + + except requests.exceptions.RequestException as e: + raise ConnectionError(f"API请求失败: {str(e)}") from e + + def test_connection(self) -> bool: + """ + Test connectivity to the model API. + + Returns: + bool: True if connection is successful + """ + try: + response = requests.get(self.base_url, headers=self.headers, timeout=10) + response.raise_for_status() + return True + except requests.RequestException as e: + logger.error(f"Model connection test failed: {str(e)}") + return False \ No newline at end of file diff --git a/yj_room_agent/__init__.py b/yj_room_agent/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/yj_room_agent/asgi.py b/yj_room_agent/asgi.py new file mode 100644 index 0000000..39ec63b --- /dev/null +++ b/yj_room_agent/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for yj_room_agent project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'yj_room_agent.settings') + +application = get_asgi_application() diff --git a/yj_room_agent/settings.py b/yj_room_agent/settings.py new file mode 100644 index 0000000..11e8212 --- /dev/null +++ b/yj_room_agent/settings.py @@ -0,0 +1,117 @@ +""" +Django settings for yj_room_agent project. + +Generated by 'django-admin startproject' using Django 5.2.1. + +For more information on this file, see +https://docs.djangoproject.com/en/5.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.2/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-i(fm5c2v*=vgfwmgdl^qi7iezv(xfwovbqu=+^=vm72e$gnx&l' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ["192.168.237.130",'127.0.0.1'] + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'yj_room_agent' +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'yj_room_agent.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'yj_room_agent.wsgi.application' + +# Database +# https://docs.djangoproject.com/en/5.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + +# Password validation +# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + +# Internationalization +# https://docs.djangoproject.com/en/5.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/5.2/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/yj_room_agent/urls.py b/yj_room_agent/urls.py new file mode 100644 index 0000000..3a82f08 --- /dev/null +++ b/yj_room_agent/urls.py @@ -0,0 +1,24 @@ +""" +URL configuration for yj_room_agent project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path +from yj_room_agent import views + +urlpatterns = [ + path('admin/', admin.site.urls), + path('test/', views.hello, name='hello'), +] diff --git a/yj_room_agent/views.py b/yj_room_agent/views.py new file mode 100644 index 0000000..e1ce54b --- /dev/null +++ b/yj_room_agent/views.py @@ -0,0 +1,5 @@ +from django.http import StreamingHttpResponse, JsonResponse, FileResponse + + +def hello(request): + return JsonResponse({'msg': 'ok'}) diff --git a/yj_room_agent/wsgi.py b/yj_room_agent/wsgi.py new file mode 100644 index 0000000..373629b --- /dev/null +++ b/yj_room_agent/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for yj_room_agent project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'yj_room_agent.settings') + +application = get_wsgi_application()