主要改动: fix(docker/dify-deploy): 修复脚本核心功能 - heredoc 单引号 bug: 'ENVEOF' 改为 ENVEOF,变量正确展开 - 端口默认值 8083/8084/8085 对齐 .env.prod 生产配置 - 加 dc_cmd() 兼容 docker-compose v1/v2 plugin - openssl rand 生成强随机密码与 SECRET_KEY(42 字符) - install 跳过已存在 .env,保护用户配置(管理员密码/SECRET_KEY) - read -p < /dev/tty 兼容非 tty 环境(CI/CD) - show-config 改用 DIFY_NGINX_PORT(nginx 入口)而非 APP_WEB_PORT docs(mvp-design): 修正 §3.2 workflow inputs 描述 - 实际只有 query,删除错误的 user_id input 声明 - 节点序列图同步更新 feat(aiChatService): 新增 Dify 客户端与适配器 - service/dify_client.go: Dify Workflow 调用 + SSE 解析 - service/dify_adapter.go: 与现有 chat_service 桥接 - provider/ai_chat_provider.go: Dubbo 入口简化 - main.go: 装配 ConversationRepository + DifyClient feat(migrations): 新增 AI 搭子会话表 ai_chat.sql - ai_conversations / ai_messages 表 + 索引 docs: 新增 Dify 集成设计文档 - 2026-06-29-ai-chat-dify-mvp-design.md (MVP 实施级) - 2026-06-29-ai-chat-dify-integration-v2-design.md (V2 演进路线图) - docs/dify/角角.yml (Workflow DSL 导出) config: 更新 env 模板与 docker 配置 - backend/.env.example: DIFY_* 环境变量声明 - docker/.env.prod: DIFY_API_BASE 对齐 8083 - docker/build.sh: 微调 - CLAUDE.md: 项目规范补充 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
70 lines
1.9 KiB
Go
70 lines
1.9 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/topfans/backend/services/aiChatService/model"
|
|
)
|
|
|
|
// DifyStreamReaderAdapter 适配 DifyStreamReader → StreamReader 接口
|
|
// DifyStreamReader.Next() returns (content, done, convID)
|
|
// StreamReader.Next() returns (content, done, error)
|
|
type DifyStreamReaderAdapter struct {
|
|
reader *DifyStreamReader
|
|
}
|
|
|
|
func (a *DifyStreamReaderAdapter) Next() (string, bool, error) {
|
|
content, done, _ := a.reader.Next()
|
|
return content, done, nil
|
|
}
|
|
|
|
func (a *DifyStreamReaderAdapter) Close() error {
|
|
return a.reader.Close()
|
|
}
|
|
|
|
// DifyAdapter Dify 适配器:适配 DifyClient → StreamReader 接口
|
|
// 将 BuildPrompt 输出的 []model.Message 转换为 Dify StreamRequest
|
|
type DifyAdapter struct {
|
|
difyClient *DifyClient
|
|
conversationID string
|
|
}
|
|
|
|
// NewDifyAdapter 创建 Dify 适配器
|
|
func NewDifyAdapter(difyClient *DifyClient) *DifyAdapter {
|
|
return &DifyAdapter{
|
|
difyClient: difyClient,
|
|
}
|
|
}
|
|
|
|
// StreamChat 将 []model.Message 转换为 Dify 流式调用
|
|
// messages 的最后一条必须是 user 消息(当前输入)
|
|
// Dify Workflow 端点不维护多轮上下文,需要通过 inputs.query 传入完整对话文本
|
|
func (s *DifyAdapter) StreamChat(ctx context.Context, messages []model.Message) (StreamReader, error) {
|
|
if len(messages) == 0 {
|
|
return nil, fmt.Errorf("empty messages")
|
|
}
|
|
|
|
// 取最后一条作为当前 query
|
|
lastMsg := messages[len(messages)-1]
|
|
if lastMsg.Role != "user" {
|
|
return nil, fmt.Errorf("last message must be user role")
|
|
}
|
|
|
|
req := StreamRequest{
|
|
Query: lastMsg.Content,
|
|
ConversationID: s.conversationID,
|
|
}
|
|
|
|
reader, err := s.difyClient.StreamChat(ctx, req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &DifyStreamReaderAdapter{reader: reader}, nil
|
|
}
|
|
|
|
// 确保接口实现正确
|
|
var _ StreamReader = (*DifyStreamReaderAdapter)(nil)
|
|
var _ io.Closer = (*DifyStreamReaderAdapter)(nil) |