📋 项目概述(源码已放在文章末尾)

这是一个完整的房树人(House-Tree-Person)心理测试AI分析系统,结合了Django后端、微信小程序前端和通义千问VL大模型。系统允许用户绘制或上传房树人图像,通过AI进行专业的心理分析,并生成详细的分析报告。技术栈涵盖:

  • 后端:Django 4.2 + Django REST Framework

  • 前端:微信小程序原生开发 + Canvas API

  • AI模型:通义千问VL大模型(图像理解能力)

  • 数据库:SQLite3(可扩展至MySQL/PostgreSQL)

  • 支付系统:完整微信支付集成

系统实现了用户绘制/上传房树人图像 → AI智能分析 → 生成专业心理报告的全流程。

🏗️ 技术架构设计

系统架构图

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│  微信小程序前端  │───▶│   Django后端API  │───▶│   AI大模型服务   │
│                 │    │                 │    │                 │
│ • Canvas绘画板  │    │ • RESTful API   │    │ • 通义千问VL     │
│ • 图片上传      │    │ • 流式响应       │    │ • 图像理解       │
│ • 支付集成      │    │ • 数据库操作     │    │ • 心理分析       │
│ • 广告组件      │    │ • 异步任务       │    │                 │
└─────────────────┘    └─────────────────┘    └─────────────────┘
                              │
                              ▼
                       ┌─────────────────┐
                       │     数据库       │
                       │                 │
                       │ • 用户记录      │
                       │ • 分析结果      │
                       │ • 订单信息      │
                       └─────────────────┘

技术架构特点

  1. 前后端分离:微信小程序前端 + Django REST API后端

  2. 流式响应:改善AI分析长时等待体验

  3. 支付集成:完整微信支付系统对接

  4. 微服务化:AI服务独立,便于扩展和替换

💻 核心技术实现

1. Canvas绘画板技术实现

微信小程序Canvas绘图
// pages/draw/draw.js - 核心绘图逻辑
Page({
  data: {
    ctx: null,
    canvas: null,
    isDrawing: false,
    lastX: 0,
    lastY: 0,
    lineWidth: 5,
    currentColor: '#2c3e50'
  },

  // 初始化Canvas - 处理高清屏适配
  initCanvas() {
    const query = wx.createSelectorQuery()
    query.select('#drawCanvas')
      .fields({ node: true, size: true })
      .exec((res) => {
        const canvas = res[0].node
        const ctx = canvas.getContext('2d')
        
        // 设备像素比适配
        const dpr = wx.getSystemInfoSync().pixelRatio
        canvas.width = res[0].width * dpr
        canvas.height = res[0].height * dpr
        
        ctx.save()
        ctx.scale(dpr, dpr)
        
        // 设置画笔属性
        ctx.lineCap = 'round'
        ctx.lineJoin = 'round'
        ctx.lineWidth = this.data.lineWidth
        ctx.strokeStyle = this.data.currentColor
        
        this.setData({ ctx, canvas })
      })
  },

  // 触摸事件处理
  touchStart(e) {
    const { x, y } = e.touches[0]
    this.setData({
      isDrawing: true,
      lastX: x,
      lastY: y
    })
  },

  touchMove(e) {
    if (!this.data.isDrawing) return
    
    const { x, y } = e.touches[0]
    const { ctx, lastX, lastY } = this.data
    
    // 贝塞尔曲线平滑绘制
    ctx.beginPath()
    ctx.moveTo(lastX, lastY)
    ctx.lineTo(x, y)
    ctx.stroke()
    
    this.setData({
      lastX: x,
      lastY: y
    })
  }
})
图片上传和适配处理
// 图片上传和Canvas绘制适配
chooseImage() {
  wx.chooseImage({
    count: 1,
    success: (res) => {
      const tempFilePath = res.tempFilePaths[0]
      const image = this.data.canvas.createImage()
      image.src = tempFilePath
      image.onload = () => {
        const { ctx, canvas } = this.data
        
        // 计算图片适配尺寸 - 保持宽高比
        const imageRatio = image.width / image.height
        const canvasRatio = canvas.width / canvas.height
        
        let drawWidth, drawHeight, x, y
        
        if (imageRatio > canvasRatio) {
          // 图片更宽,以宽度为基准
          drawWidth = canvas.width
          drawHeight = canvas.width / imageRatio
          x = 0
          y = (canvas.height - drawHeight) / 2
        } else {
          // 图片更高,以高度为基准
          drawHeight = canvas.height
          drawWidth = canvas.height * imageRatio
          x = (canvas.width - drawWidth) / 2
          y = 0
        }
        
        // 清除画布并绘制图片
        ctx.clearRect(0, 0, canvas.width, canvas.height)
        ctx.drawImage(image, x, y, drawWidth, drawHeight)
      }
    }
  })
}

2. Django后端AI分析系统

核心分析接口实现
# apps/users/views.py - AI分析核心逻辑
@csrf_exempt
@require_http_methods(["POST"])
def analyze(request):
    try:
        # 解析请求数据
        data = json.loads(request.body)
        image_data = data.get('image')
        
        if not image_data:
            return JsonResponse({'error': '未接收到图片数据'}, status=400)

        # 初始化通义千问VL大模型
        model = ChatOpenAI(
            model="qwen3-vl-plus", 
            openai_api_key=settings.OPENAI_API_KEY, 
            temperature=0.0, 
            request_timeout=300, 
            max_retries=1, 
            max_tokens=8192, 
            base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
        )
        
        # 构建心理学分析Prompt
        prompt = ChatPromptTemplate.from_messages([
            ("system", config.PROMPT_INSTRUCTIONS_HTML),
            ("user", [
                {"type": "text", "text": "这是我画的,请帮我分析"},
                {"type": "image_url", "image_url": {"url": f"{image_data}"}},
            ]),
        ])
        
        chain = prompt | model

        # 流式响应生成器 - 实时返回分析结果
        def generate():
            analysis_results = ''
            for chunk in chain.stream({"image_data": image_data}):
                analysis_results += chunk.content
                yield json.dumps({
                    'type': 'text',
                    'content': chunk.content
                }) + '\n'
            
            # 保存分析记录到数据库
            record = AnalysisRecord.objects.create(
                image_data=image_data,
                analysis_result=analysis_results,
                request_time=datetime.now(),
                process_duration=(datetime.now() - request_start_time).total_seconds(),
                payment_status='unpaid'
            )
            
            yield json.dumps({
                'type': 'objectID',
                'content': f"{str(record.id)}"
            }) + '\n'

        # 返回流式HTTP响应
        return StreamingHttpResponse(generate(), content_type='application/json')
        
    except Exception as e:
        logger.error(f"分析失败: {str(e)}")
        return JsonResponse({'error': str(e)}, status=500)
数据库模型设计
# apps/users/models.py - 数据模型设计
class AnalysisRecord(models.Model):
    """房树人测试分析记录"""
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    image_data = models.TextField(verbose_name="图片数据")
    analysis_result = models.TextField(verbose_name="分析结果")
    request_time = models.DateTimeField(verbose_name="请求时间")
    process_duration = models.FloatField(verbose_name="处理用时(秒)")
    payment_status = models.CharField(
        max_length=20, 
        default="unpaid", 
        verbose_name="支付状态",
        choices=[("unpaid", "未支付"), ("paid", "已支付")]
    )
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    
    class Meta:
        verbose_name = "分析记录"
        verbose_name_plural = "分析记录"
        ordering = ['-created_at']
    
    def __str__(self):
        return f"分析记录 {self.id} - {self.payment_status}"


class HTPOrder(models.Model):
    """房树人测试订单"""
    out_trade_no = models.CharField(max_length=100, unique=True, verbose_name="订单号")
    status = models.CharField(
        max_length=20, 
        default="unpaid", 
        verbose_name="订单状态",
        choices=[("unpaid", "未支付"), ("paid", "已支付")]
    )
    timestamp = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    
    class Meta:
        verbose_name = "订单"
        verbose_name_plural = "订单"
        ordering = ['-timestamp']
    
    def __str__(self):
        return f"订单 {self.out_trade_no} - {self.status}"

3. AI Prompt工程实现

心理学分析Prompt设计
# config.py - 专业心理学Prompt设计
PROMPT_INSTRUCTIONS_HTML = """# Role
心理测试分析师,分析用户绘制的房树人测试图,提供个性化解读和心理建议。

## Action
模型基于用户提供的房树人测试图,逐一分析房子、树和人物的细节、结构、比例、位置以及其他特征。通过这些元素的分析,评估用户的心理状态、性格特征、潜在情感需求,并给出针对性的心理暗示与建议。

## Skills
- 扎实的心理学理论基础,尤其是在投射测试和心理评估方面
- 优秀的观察力和敏锐的心理分析能力,能够解读绘画中的微妙心理信号
- 精确的语言表达与总结能力,能够将复杂的心理信息转化为通俗易懂的分析结果
- 熟练掌握房树人测试的框架和解读方法
- 能够灵活应对不同绘画风格,适应性地调整分析角度

## Format
- 输出结果使用HTML排版,确保内容结构清晰,易于用户阅读。
- 每个分析部分(如房子、树、人物等)需分别作为一个独立的`div`区块,包含标题和具体分析内容。
- 每个分析内容分为小节,涵盖具体的心理解读,并在适当位置加入心理暗示和总结建议。
- 分析内容应简洁明了,避免复杂的心理学术语,确保用户易于理解。
- 每段文字都必须使用标签包裹,以便于前端解析。

## Constraints
- 每个分析部分需包含详细的心理解读,并根据绘画的细节、比例、结构等给出具体的建议。
- 保证分析结果层次分明,每个部分都应清晰标明标题和分析内容。
- 内容应具有较高的专业性,但避免过于学术化,语言要易于理解。
- HTML排版结构需语义化,确保便于网页呈现和用户浏览。
"""

4. 支付系统技术实现

微信小程序支付集成
// pages/report/report.js - 支付功能实现
getPayOrderId() {
  const that = this
  const secretKey = 'ylA82pMGHHkUYXw0Mgb5xasXQoScPX8n'
  const resultId = this.data.resultId

  var params = {
    pid: '20230210011731',
    cid: '10450',
    type: 'wxpay',
    out_trade_no: resultId,
    notify_url: app.globalData.host + '/htp/api/payment_notification_by_no',
    name: '房树人心理测试',
    money: that.data.price,
    clientip: '192.168.1.100',
    device: 'pc',
    param: resultId,
    sign_type: 'MD5',
  };
  
  // 生成MD5签名
  const sign = generateSign(params, secretKey);
  params.sign = sign;
  
  // 调用支付接口
  wx.request({
    url: 'https://zpayz.cn/mapi.php',
    method: 'POST',
    data: params,
    header: {
        'content-type': 'application/x-www-form-urlencoded'
    },
    success(res) {
      if(res.data && res.data.code === 1) {
        // 显示支付二维码
        that.setData({
          qrCodeImage: res.data.img
        });

        // 轮询查询支付状态
        const intervalId = setInterval(() => {
          wx.request({
            url: app.globalData.host + '/htp/api/check_payment_status_by_no',
            method: 'GET',
            data: { out_trade_no: resultId },
            success(response) {
              if (response.data.payment_status === 'paid') {
                clearInterval(intervalId);
                that.setData({ loading: true });
                that.analyzeDrawing(); // 支付成功后调用分析
              }
            }
          });
        }, 2000);
      }
    }
  });
}
Django支付回调处理
# apps/users/views.py - 支付回调接口
@require_http_methods(["GET"])
def payment_notification_by_no(request):
    try:
        # 获取所有请求参数
        params = request.GET.dict()
        print("接收到的支付通知参数:", params)

        # 从参数中获取param值
        param = params.get('param')

        # 检查交易状态
        trade_status = params.get('trade_status')
        if trade_status == 'TRADE_SUCCESS':
            # 创建或更新订单记录
            order, created = HTPOrder.objects.get_or_create(
                out_trade_no=param,
                defaults={'status': 'paid'}
            )
            if not created:
                order.status = 'paid'
                order.save()
            print(f"订单记录 {param} 添加/更新成功")

        # 返回成功响应
        return HttpResponse('success')
    except Exception as e:
        return JsonResponse({'error': str(e)}, status=500)

5. 流式响应处理技术

前端流式响应解析
// 流式响应处理 - 实时显示AI分析结果
analyzeDrawing() {
  const startTime = Date.now()
  const that = this
  
  wx.request({
    url: app.globalData.host + '/htp/api/analyze',
    method: 'POST',
    data: { image: this.data.drawingImage },
    timeout: 180000,
    responseType: 'text',
    success(res) {
      const lines = res.data.split('\n')
      let content = ''
      
      for (const line of lines) {
        if (!line.trim()) continue
        try {
          const data = JSON.parse(line)
          if (data.type === 'text') {
            // 处理HTML内容
            let processedContent = data.content
              .replaceAll('```', '')
              .replaceAll('html', '')
              .replaceAll('<h4>', '<h4 style="border-left: 4px solid #4a90e2;padding-left: 15px;color:#4a90e2;margin: 20px 0;">')
            
            content += processedContent
          }
        } catch (e) {
          console.error('解析错误:', e)
        }
      }
      
      that.setData({
        loading: false,
        analysisContent: content,
        analysisTime: ((Date.now() - startTime) / 1000).toFixed(2)
      })
    }
  })
}

🔧 部署与配置

1. 环境配置

# 安装Python依赖
pip install -r requirements.txt

# 数据库迁移
python manage.py migrate

2. Django配置

# settings.py - 关键配置
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'django_celery_results',
    'apps.users'
]

# Celery配置
CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'Asia/Shanghai'

3. 启动服务

# 启动Django服务
python manage.py runserver 0.0.0.0:8000

📈 项目总结

技术亮点

  1. 全栈开发:完整的Django后端 + 微信小程序前端

  2. AI集成:通义千问VL大模型的深度集成

  3. 流式响应:改善用户体验的实时反馈机制

  4. 支付系统:完整微信支付集成

  5. 跨平台:微信小程序的多设备兼容性

学习价值

通过这个项目,开发者可以学习到:

  • Django REST Framework的API设计

  • 微信小程序Canvas绘图技术

  • AI大模型的集成与应用

  • 流式响应的实现原理

  • 支付系统对接技术

  • 生产环境的部署和优化

应用场景

  1. 心理教育:学校心理辅导工具

  2. 自我认知:个人心理状态评估

  3. 心理咨询:专业咨询师的辅助工具

  4. 社交娱乐:朋友间的心理测试游戏

📦 获取源码

完整的项目源码已经整理好,包含:

  • 完整的Django后端代码

  • 微信小程序前端代码

  • 数据库迁移文件

  • 部署配置脚本

  • 详细的开发文档

  • 支付系统对接代码

关注公众号【AI创业指南】,回复【房树人源码】即可获取完整项目源码。

💬 技术交流

如果在部署或使用过程中遇到任何技术问题,欢迎通过以下方式交流:

  1. 在公众号留言技术问题

希望这个项目能为你提供有价值的技术参考,也欢迎提出技术改进建议和功能需求。


立即获取源码,开始你的全栈AI项目开发之旅!

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐