UPDATE
This commit is contained in:
+78
-10
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
ویوهای RAG — چت با استریم
|
||||
"""
|
||||
import json
|
||||
import logging
|
||||
|
||||
from django.http import StreamingHttpResponse
|
||||
@@ -13,6 +14,7 @@ from drf_spectacular.utils import (
|
||||
)
|
||||
from rest_framework import status
|
||||
from rest_framework import serializers as drf_serializers
|
||||
from rest_framework.parsers import FormParser, JSONParser, MultiPartParser
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
@@ -22,7 +24,7 @@ from config.openapi import (
|
||||
build_message_response_serializer,
|
||||
build_response,
|
||||
)
|
||||
from .chat import chat_rag_stream
|
||||
from .chat import chat_rag_stream, encode_uploaded_image
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -47,11 +49,45 @@ RagFertilizationResponseSerializer = build_envelope_serializer(
|
||||
|
||||
|
||||
class ChatView(APIView):
|
||||
"""
|
||||
چت RAG با استریم.
|
||||
POST با {"query": "متن سوال", "farm_uuid": "شناسه مزرعه"}.
|
||||
همیشه از سرویس ثابت `chat` استفاده میکند و اطلاعات مزرعه را مستقیم به مدل میفرستد.
|
||||
"""
|
||||
parser_classes = [JSONParser, MultiPartParser, FormParser]
|
||||
|
||||
def _parse_history(self, raw_history):
|
||||
if raw_history in (None, "", []):
|
||||
return []
|
||||
if isinstance(raw_history, list):
|
||||
return raw_history
|
||||
if isinstance(raw_history, str):
|
||||
try:
|
||||
parsed = json.loads(raw_history)
|
||||
except (json.JSONDecodeError, ValueError):
|
||||
raise ValueError("history باید JSON معتبر باشد.")
|
||||
if not isinstance(parsed, list):
|
||||
raise ValueError("history باید آرایه باشد.")
|
||||
return parsed
|
||||
raise ValueError("history فرمت پشتیبانی شده ندارد.")
|
||||
|
||||
def _collect_uploaded_images(self, request: Request):
|
||||
images = []
|
||||
for uploaded in request.FILES.getlist("images"):
|
||||
images.append(encode_uploaded_image(uploaded))
|
||||
single_image = request.FILES.get("image")
|
||||
if single_image is not None:
|
||||
images.append(encode_uploaded_image(single_image))
|
||||
image_urls = request.data.get("image_urls")
|
||||
if isinstance(image_urls, str) and image_urls.strip():
|
||||
try:
|
||||
parsed_urls = json.loads(image_urls)
|
||||
except (json.JSONDecodeError, ValueError):
|
||||
parsed_urls = [image_urls]
|
||||
image_urls = parsed_urls
|
||||
if isinstance(image_urls, list):
|
||||
for item in image_urls:
|
||||
if isinstance(item, str) and item.strip():
|
||||
images.append({"url": item.strip(), "detail": "auto"})
|
||||
elif isinstance(item, dict) and isinstance(item.get("url"), str):
|
||||
image_payload = {"url": item["url"].strip(), "detail": item.get("detail", "auto")}
|
||||
images.append(image_payload)
|
||||
return images
|
||||
|
||||
@extend_schema(
|
||||
tags=["RAG Chat"],
|
||||
@@ -63,6 +99,14 @@ class ChatView(APIView):
|
||||
"query": drf_serializers.CharField(required=False, help_text="متن سوال کاربر"),
|
||||
"message": drf_serializers.CharField(required=False, help_text="نام قبلی فیلد query"),
|
||||
"farm_uuid": drf_serializers.CharField(help_text="شناسه مزرعه"),
|
||||
"history": drf_serializers.JSONField(required=False, help_text="آرایه پیام های قبلی با role=user/assistant"),
|
||||
"image_urls": drf_serializers.JSONField(required=False, help_text="آرایه URL تصاویر برای پیام فعلی"),
|
||||
"image": drf_serializers.FileField(required=False, help_text="یک تصویر برای پیام فعلی"),
|
||||
"images": drf_serializers.ListField(
|
||||
child=drf_serializers.FileField(),
|
||||
required=False,
|
||||
help_text="چند تصویر برای پیام فعلی",
|
||||
),
|
||||
},
|
||||
),
|
||||
responses={
|
||||
@@ -83,8 +127,13 @@ class ChatView(APIView):
|
||||
OpenApiExample(
|
||||
"نمونه درخواست",
|
||||
value={
|
||||
"farm_uuid": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"farm_uuid": "11111111-1111-1111-1111-111111111111",
|
||||
"query": "وضعیت مزرعه من چطور است؟",
|
||||
"history": [
|
||||
{"role": "user", "content": "رطوبت خاک من پایین بود؟"},
|
||||
{"role": "assistant", "content": "بله، رطوبت خاک کمتر از محدوده مطلوب بود."},
|
||||
],
|
||||
"image_urls": ["https://example.com/farm-photo.jpg"],
|
||||
},
|
||||
request_only=True,
|
||||
),
|
||||
@@ -97,9 +146,19 @@ class ChatView(APIView):
|
||||
data = request.data if request.method == "POST" else request.query_params
|
||||
message = data.get("query", data.get("message"))
|
||||
farm_uuid = data.get("farm_uuid")
|
||||
raw_history = data.get("history")
|
||||
try:
|
||||
images = self._collect_uploaded_images(request)
|
||||
except ValueError as exc:
|
||||
return Response(
|
||||
{"code": 400, "msg": str(exc)},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
if message is None and images:
|
||||
message = "لطفا تصویر ارسالی را در کنار اطلاعات مزرعه بررسی کن."
|
||||
if not message or not isinstance(message, str):
|
||||
return Response(
|
||||
{"code": 400, "msg": "پارامتر query الزامی است."},
|
||||
{"code": 400, "msg": "پارامتر query الزامی است، مگر اینکه تصویر ارسال شده باشد."},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
message = str(message).strip()
|
||||
@@ -119,6 +178,13 @@ class ChatView(APIView):
|
||||
{"code": 400, "msg": "farm_uuid نباید خالی باشد."},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
try:
|
||||
history = self._parse_history(raw_history)
|
||||
except ValueError as exc:
|
||||
return Response(
|
||||
{"code": 400, "msg": str(exc)},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
cfg = load_rag_config()
|
||||
farm_details = get_farm_details(farm_uuid)
|
||||
if farm_details is None:
|
||||
@@ -134,6 +200,8 @@ class ChatView(APIView):
|
||||
farm_uuid=farm_uuid,
|
||||
config=cfg,
|
||||
farm_details=farm_details,
|
||||
history=history,
|
||||
images=images,
|
||||
):
|
||||
yield chunk
|
||||
except Exception as e:
|
||||
@@ -188,7 +256,7 @@ class IrrigationRecommendationView(APIView):
|
||||
OpenApiExample(
|
||||
"نمونه درخواست",
|
||||
value={
|
||||
"farm_uuid": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"farm_uuid": "11111111-1111-1111-1111-111111111111",
|
||||
"plant_name": "گوجهفرنگی",
|
||||
"growth_stage": "میوهدهی",
|
||||
"irrigation_method_name": "آبیاری قطرهای",
|
||||
@@ -270,7 +338,7 @@ class FertilizationRecommendationView(APIView):
|
||||
OpenApiExample(
|
||||
"نمونه درخواست",
|
||||
value={
|
||||
"farm_uuid": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"farm_uuid": "11111111-1111-1111-1111-111111111111",
|
||||
"plant_name": "گوجهفرنگی",
|
||||
"growth_stage": "رویشی",
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user