├── .gitignore
├── README.md
├── assets
└── book.png
├── ddd-aigc-application-service
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── feiniaojin
│ │ │ └── ddd
│ │ │ └── aigc
│ │ │ └── application
│ │ │ └── service
│ │ │ ├── .gitkeep
│ │ │ ├── GenerateContentDomainServiceImpl.java
│ │ │ ├── diary
│ │ │ ├── DiaryCommandApplicationService.java
│ │ │ ├── DiaryEntityFactoryImpl.java
│ │ │ ├── DiaryQueryApplicationService.java
│ │ │ └── dto
│ │ │ │ ├── DiaryCreateCommand.java
│ │ │ │ ├── DiaryCreateView.java
│ │ │ │ ├── DiaryQuery.java
│ │ │ │ ├── DiarySaveContentCommand.java
│ │ │ │ └── DiaryView.java
│ │ │ └── stickynote
│ │ │ ├── StickyNoteCommandApplicationService.java
│ │ │ ├── StickyNoteEntityFactoryImpl.java
│ │ │ ├── StickyNoteQueryApplicationService.java
│ │ │ └── dto
│ │ │ ├── StickyNoteCreateCommand.java
│ │ │ ├── StickyNoteCreateView.java
│ │ │ ├── StickyNoteGenerateContentQuery.java
│ │ │ ├── StickyNoteGenerateContentView.java
│ │ │ ├── StickyNoteModifyCommand.java
│ │ │ ├── StickyNoteQuery.java
│ │ │ └── StickyNoteView.java
│ └── resources
│ │ └── .gitkeep
│ └── test
│ └── java
│ └── com
│ └── feiniaojin
│ └── ddd
│ └── aigc
│ └── application
│ └── service
│ └── test
│ └── .gitkeep
├── ddd-aigc-domain
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── com
│ │ └── feiniaojin
│ │ └── ddd
│ │ └── aigc
│ │ └── domain
│ │ ├── .gitkeep
│ │ ├── DiaryEntity.java
│ │ ├── DiaryEntityFactory.java
│ │ ├── DiaryEntityId.java
│ │ ├── DiaryEntityRepository.java
│ │ ├── LlmGateway.java
│ │ ├── StickyNoteEntity.java
│ │ ├── StickyNoteEntityFactory.java
│ │ ├── StickyNoteEntityId.java
│ │ ├── StickyNoteEntityRepository.java
│ │ └── StickyNoteGenerateContentDomainService.java
│ └── test
│ └── java
│ └── com
│ └── feiniaojin
│ └── ddd
│ └── aigc
│ └── domain
│ └── test
│ └── .gitkeep
├── ddd-aigc-frontend
├── .gitattributes
├── .gitignore
├── .prettierrc.json
├── README.md
├── index.html
├── jsconfig.json
├── package-lock.json
├── package.json
├── public
│ └── favicon.ico
├── src
│ ├── App.vue
│ ├── api
│ │ ├── diary.js
│ │ └── stickynote.js
│ ├── assets
│ │ ├── base.css
│ │ ├── logo.svg
│ │ └── main.css
│ ├── components
│ │ ├── HelloWorld.vue
│ │ ├── TheWelcome.vue
│ │ ├── WelcomeItem.vue
│ │ └── icons
│ │ │ ├── IconCommunity.vue
│ │ │ ├── IconDocumentation.vue
│ │ │ ├── IconEcosystem.vue
│ │ │ ├── IconSupport.vue
│ │ │ └── IconTooling.vue
│ ├── main.js
│ ├── router
│ │ └── index.js
│ ├── store
│ │ └── info.js
│ ├── utils
│ │ ├── request.js
│ │ └── storage.js
│ └── views
│ │ ├── AboutView.vue
│ │ ├── BasicInfo.vue
│ │ ├── Content.vue
│ │ ├── HomeView.vue
│ │ └── WhiteBoard.vue
└── vite.config.js
├── ddd-aigc-infrastructure-cache
├── pom.xml
└── src
│ └── main
│ └── java
│ └── com
│ └── feiniaojin
│ └── Main.java
├── ddd-aigc-infrastructure-gateway
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── feiniaojin
│ │ │ └── ddd
│ │ │ └── aigc
│ │ │ └── infrastructure
│ │ │ └── gateway
│ │ │ ├── .gitkeep
│ │ │ ├── LlmConfig.java
│ │ │ ├── LlmGatewayImpl.java
│ │ │ └── llm
│ │ │ ├── AbstractLlmProviderImpl.java
│ │ │ ├── DeepSeekLlmProviderImpl.java
│ │ │ ├── LlmProvider.java
│ │ │ ├── LlmProviderRegister.java
│ │ │ ├── OllamaLlmProviderImpl.java
│ │ │ ├── OpenAiLlmProviderImpl.java
│ │ │ └── SiliconflowLlmProviderImpl.java
│ └── resources
│ │ └── .gitkeep
│ └── test
│ ├── java
│ └── com
│ │ └── feiniaojin
│ │ └── ddd
│ │ └── aigc
│ │ └── infrastructure
│ │ └── gateway
│ │ └── .gitkeep
│ └── resources
│ └── .gitkeep
├── ddd-aigc-infrastructure-persistence
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── feiniaojin
│ │ │ └── ddd
│ │ │ └── aigc
│ │ │ └── infrastructure
│ │ │ └── persistence
│ │ │ ├── .gitkeep
│ │ │ ├── DiaryEntityRepositoryImpl.java
│ │ │ ├── JdbcConfig.java
│ │ │ ├── StickyNoteEntityRepositoryImpl.java
│ │ │ ├── data
│ │ │ ├── Diary.java
│ │ │ └── StickyNote.java
│ │ │ ├── jdbc
│ │ │ ├── DiaryJdbcRepository.java
│ │ │ └── StickyNoteJdbcRepository.java
│ │ │ └── mapper
│ │ │ ├── DiaryMapper.java
│ │ │ └── StickyNoteMapper.java
│ └── resources
│ │ ├── .gitkeep
│ │ ├── ddd-aigc.sql
│ │ └── mappers
│ │ ├── DiaryMapper.xml
│ │ └── StickyNoteMapper.xml
│ └── test
│ ├── java
│ └── com
│ │ └── feiniaojin
│ │ └── ddd
│ │ └── aigc
│ │ └── infrastructure
│ │ └── persistence
│ │ └── .gitkeep
│ └── resources
│ └── .gitkeep
├── ddd-aigc-infrastructure-publisher
└── pom.xml
├── ddd-aigc-launcher
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── feiniaojin
│ │ │ └── ddd
│ │ │ └── aigc
│ │ │ └── Launcher.java
│ └── resources
│ │ ├── .gitkeep
│ │ └── application.yaml
│ └── test
│ ├── java
│ └── com
│ │ └── feiniaojin
│ │ └── ddd
│ │ └── aigc
│ │ └── launcher
│ │ └── test
│ │ └── .gitkeep
│ └── resources
│ └── .gitkeep
├── ddd-aigc-user-interface-provider
├── pom.xml
└── src
│ └── main
│ └── java
│ └── com
│ └── feiniaojin
│ └── Main.java
├── ddd-aigc-user-interface-subscriber
├── pom.xml
└── src
│ └── main
│ └── java
│ └── com
│ └── feiniaojin
│ └── Main.java
├── ddd-aigc-user-interface-web
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── feiniaojin
│ │ │ └── ddd
│ │ │ └── aigc
│ │ │ └── ui
│ │ │ └── web
│ │ │ ├── .gitkeep
│ │ │ ├── WebConfig.java
│ │ │ └── controller
│ │ │ ├── DiaryController.java
│ │ │ └── StickyNoteController.java
│ └── resources
│ │ └── .gitkeep
│ └── test
│ ├── java
│ └── com
│ │ └── feiniaojin
│ │ └── ddd
│ │ └── aigc
│ │ └── ui
│ │ └── web
│ │ └── test
│ │ └── .gitkeep
│ └── resources
│ └── .gitkeep
├── ddd-aigc-user-interface-worker
├── pom.xml
└── src
│ └── main
│ └── java
│ └── com
│ └── feiniaojin
│ └── Main.java
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.nar
17 | *.ear
18 | *.zip
19 | *.tar.gz
20 | *.rar
21 |
22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
23 | hs_err_pid*
24 | replay_pid*
25 | .idea
26 | target/
27 | node_modules/
28 | .vscode/
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://imgse.com/i/pinWT1A)
2 |
3 | # DDD-AIGC
4 |
5 | 本项目是作者的新书《悟道领域驱动设计》的随书案例代码。《悟道领域驱动设计》目前已上架各大电商平台,感兴趣的朋友可以帮忙支持一下。
6 |
7 |
8 |
9 | 购买链接:https://item.jd.com/14835288.html
10 |
11 | 本项目实现了一个贴纸日记的AIGC应用。
12 |
13 | 当用户需要记日记时,在一张贴纸上写下事情和参与者,系统会用ChatGPT生成日记正文。
14 |
15 | 原型图如下:
16 |
17 | [](https://imgse.com/i/pinW76I)
18 |
19 | # 技术栈
20 |
21 | - SpringBoot
22 | - MyBatis、Spring Data JDBC
23 | - Graceful-Response
24 | ```text
25 | https://github.com/feiniaojin/graceful-response
26 | ```
27 | - ddd-archetype
28 | ```text
29 | https://github.com/feiniaojin/ddd-archetype
30 | ```
31 | - MySQL
32 | - ChatGPT
33 |
34 | # 运行截图
35 |
36 | [](https://imgse.com/i/pinWL0f)
37 |
38 | # 贡献者
39 |
40 |
41 |
42 |
43 | # 点赞趋势
44 |
45 | [](https://star-history.com/#feiniaojin/ddd-aigc&Date)
46 |
47 | # DDD学习交流群
48 | 欢迎加入DDD交流群。微信扫以下二维码添加作者微信,标注“DDD”,好友申请通过后拉您进群。
49 |
50 |
--------------------------------------------------------------------------------
/assets/book.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/assets/book.png
--------------------------------------------------------------------------------
/ddd-aigc-application-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ddd-aigc
5 | com.feiniaojin.ddd.aigc
6 | 1.0-SNAPSHOT
7 |
8 | 4.0.0
9 |
10 | ddd-aigc-application-service
11 |
12 | 应用服务层,依赖domain和infrastructure,不包含业务逻辑,协调领域模型完成业务逻辑,并使用基础设置为业务提供支持
13 |
14 |
15 | 8
16 | 8
17 |
18 |
19 |
20 |
21 | com.feiniaojin.ddd.aigc
22 | ddd-aigc-domain
23 |
24 |
25 | com.feiniaojin.ddd.aigc
26 | ddd-aigc-infrastructure-gateway
27 |
28 |
29 | com.feiniaojin.ddd.aigc
30 | ddd-aigc-infrastructure-cache
31 |
32 |
33 | com.feiniaojin.ddd.aigc
34 | ddd-aigc-infrastructure-persistence
35 |
36 |
37 | com.feiniaojin.ddd.aigc
38 | ddd-aigc-infrastructure-publisher
39 |
40 |
41 | org.springframework
42 | spring-context
43 |
44 |
45 | org.springframework
46 | spring-beans
47 |
48 |
49 | com.feiniaojin
50 | graceful-response
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/GenerateContentDomainServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service;
2 |
3 | import com.feiniaojin.ddd.aigc.domain.*;
4 | import com.feiniaojin.ddd.aigc.infrastructure.persistence.jdbc.StickyNoteJdbcRepository;
5 | import jakarta.annotation.Resource;
6 | import org.springframework.stereotype.Service;
7 | import org.springframework.util.CollectionUtils;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | @Service
13 | public class GenerateContentDomainServiceImpl implements StickyNoteGenerateContentDomainService {
14 |
15 | @Resource
16 | private LlmGateway llmGateway;
17 |
18 | @Resource
19 | private StickyNoteJdbcRepository stickyNoteJdbcRepository;
20 |
21 | @Resource
22 | private StickyNoteEntityRepository noteEntityRepository;
23 |
24 | /**
25 | * 经典领域驱动对领域服务的定义
26 | *
27 | * @param diaryEntityId
28 | * @return
29 | */
30 | @Override
31 | public String generateContent(DiaryEntityId diaryEntityId, String userInput) {
32 |
33 | //1.加载日记下的所有贴纸
34 | List noteIdList = stickyNoteJdbcRepository.queryStickyNoteIdByDiaryId(diaryEntityId.getValue());
35 | if (CollectionUtils.isEmpty(noteIdList)) {
36 | return "";
37 | }
38 |
39 | List stickyNoteEntities = new ArrayList<>();
40 | //2.加载领域模型
41 | for (String noteId : noteIdList) {
42 | StickyNoteEntity stickyNoteEntity = noteEntityRepository.load(new StickyNoteEntityId(noteId));
43 | stickyNoteEntities.add(stickyNoteEntity);
44 | }
45 |
46 | //2.根据贴纸聚合的集合,生成文本
47 | return llmGateway.generateContent(stickyNoteEntities, userInput);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/diary/DiaryCommandApplicationService.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.diary;
2 |
3 | import com.feiniaojin.ddd.aigc.application.service.diary.dto.DiaryCreateCommand;
4 | import com.feiniaojin.ddd.aigc.application.service.diary.dto.DiaryCreateView;
5 | import com.feiniaojin.ddd.aigc.application.service.diary.dto.DiarySaveContentCommand;
6 | import com.feiniaojin.ddd.aigc.domain.DiaryEntity;
7 | import com.feiniaojin.ddd.aigc.domain.DiaryEntityFactory;
8 | import com.feiniaojin.ddd.aigc.domain.DiaryEntityId;
9 | import com.feiniaojin.ddd.aigc.domain.DiaryEntityRepository;
10 | import jakarta.annotation.Resource;
11 | import org.springframework.stereotype.Service;
12 |
13 |
14 | @Service
15 | public class DiaryCommandApplicationService {
16 |
17 | @Resource
18 | private DiaryEntityFactory factory;
19 |
20 | @Resource
21 | private DiaryEntityRepository repository;
22 |
23 | public DiaryCreateView createDiary(DiaryCreateCommand command) {
24 |
25 | DiaryEntity diary = factory.newInstance(command.getUid(), command.getDiaryDate());
26 | //执行业务上的创建逻辑
27 | diary.create();
28 |
29 | repository.save(diary);
30 |
31 | return new DiaryCreateView(diary.getDiaryEntityId().getValue());
32 | }
33 |
34 | public void saveContent(DiarySaveContentCommand command) {
35 |
36 | DiaryEntity diaryEntity = repository.load(new DiaryEntityId(command.getDiaryId()));
37 | diaryEntity.modifyContent(command.getContent());
38 | repository.save(diaryEntity);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/diary/DiaryEntityFactoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.diary;
2 |
3 | import com.feiniaojin.ddd.aigc.domain.DiaryEntity;
4 | import com.feiniaojin.ddd.aigc.domain.DiaryEntityFactory;
5 | import com.feiniaojin.ddd.aigc.domain.DiaryEntityId;
6 | import org.apache.commons.lang3.RandomStringUtils;
7 | import org.apache.commons.lang3.StringUtils;
8 | import org.springframework.stereotype.Component;
9 |
10 | import java.text.DateFormat;
11 | import java.text.SimpleDateFormat;
12 | import java.util.Date;
13 |
14 | @Component
15 | public class DiaryEntityFactoryImpl implements DiaryEntityFactory {
16 | @Override
17 | public DiaryEntity newInstance(String uid, String diaryDateStr) {
18 |
19 | DiaryEntity diaryEntity = new DiaryEntity();
20 |
21 | diaryEntity.setUid(uid);
22 |
23 | if (StringUtils.isBlank(diaryDateStr)) {
24 | throw new IllegalArgumentException("diaryDate为空");
25 | }
26 | try {
27 | DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
28 | Date parse = dateFormat.parse(diaryDateStr);
29 | diaryEntity.setDiaryDate(parse);
30 | diaryEntity.setDiaryDateStr(diaryDateStr);
31 | } catch (Exception e) {
32 | throw new RuntimeException(e);
33 | }
34 | String did = RandomStringUtils.randomAlphabetic(9);
35 | diaryEntity.setDiaryEntityId(new DiaryEntityId(did));
36 | //维护层超类型
37 | diaryEntity.setDeleted(0);
38 | Date date = new Date();
39 | diaryEntity.setCreatedDate(date);
40 | diaryEntity.setLastModifiedDate(date);
41 | return diaryEntity;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/diary/DiaryQueryApplicationService.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.diary;
2 |
3 | import com.feiniaojin.ddd.aigc.application.service.diary.dto.DiaryQuery;
4 | import com.feiniaojin.ddd.aigc.application.service.diary.dto.DiaryView;
5 | import com.feiniaojin.ddd.aigc.infrastructure.persistence.data.Diary;
6 | import com.feiniaojin.ddd.aigc.infrastructure.persistence.mapper.DiaryMapper;
7 | import com.feiniaojin.gracefulresponse.data.PageBean;
8 | import jakarta.annotation.Resource;
9 | import org.springframework.stereotype.Service;
10 |
11 | import java.util.ArrayList;
12 | import java.util.HashMap;
13 | import java.util.List;
14 | import java.util.Map;
15 |
16 | @Service
17 | public class DiaryQueryApplicationService {
18 |
19 | @Resource
20 | private DiaryMapper diaryMapper;
21 |
22 | public PageBean pageList(DiaryQuery query) {
23 |
24 | PageBean pageBean = new PageBean<>();
25 | pageBean.setPage(query.getPage());
26 | pageBean.setPageSize(query.getPageSize());
27 |
28 | Map paramMap = new HashMap<>();
29 |
30 | int count = diaryMapper.countForPageList(paramMap);
31 | pageBean.setTotal(count);
32 | if (count == 0) {
33 | return pageBean;
34 | }
35 | paramMap.put("limitStart", (query.getPage() - 1) * query.getPageSize());
36 | paramMap.put("limitEnd", query.getPageSize());
37 |
38 | List liveList = diaryMapper.pageList(paramMap);
39 | List views = this.dataToView(liveList);
40 |
41 | pageBean.setList(views);
42 | pageBean.setTotal(count);
43 | return pageBean;
44 | }
45 |
46 | private List dataToView(List list) {
47 |
48 | List views = new ArrayList<>(list.size());
49 |
50 | for (Diary d : list) {
51 | DiaryView view = new DiaryView();
52 | view.setUid(d.getUid());
53 | view.setContent(d.getContent());
54 | view.setDiaryId(d.getDiaryId());
55 | view.setDiaryDateStr(d.getDiaryDateStr());
56 | views.add(view);
57 | }
58 |
59 | return views;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/diary/dto/DiaryCreateCommand.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.diary.dto;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class DiaryCreateCommand {
7 |
8 | /**
9 | * 写日记的当天
10 | * 按照格式传过来yyyyMMdd
11 | */
12 | private String diaryDate;
13 |
14 | /**
15 | * 用户id
16 | */
17 | private String uid;
18 | }
19 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/diary/dto/DiaryCreateView.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.diary.dto;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class DiaryCreateView {
7 | private String diaryId;
8 |
9 | public DiaryCreateView(String diaryId) {
10 | this.diaryId = diaryId;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/diary/dto/DiaryQuery.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.diary.dto;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class DiaryQuery {
7 | private Integer pageSize = 10;
8 |
9 | private Integer page = 1;
10 | }
11 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/diary/dto/DiarySaveContentCommand.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.diary.dto;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class DiarySaveContentCommand {
7 |
8 | /**
9 | * 日记ID
10 | */
11 | private String diaryId;
12 |
13 | /**
14 | * 用户id
15 | */
16 | private String uid;
17 |
18 | /**
19 | * AI生成的内容
20 | */
21 | private String content;
22 | }
23 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/diary/dto/DiaryView.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.diary.dto;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class DiaryView {
7 |
8 | private String diaryId;
9 |
10 | private String content;
11 |
12 | /**
13 | * 日记对应的时间,字符串,yyyyMMDD
14 | */
15 | private String diaryDateStr;
16 |
17 | /**
18 | * 用户ID
19 | */
20 | private String uid;
21 | }
22 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/stickynote/StickyNoteCommandApplicationService.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.stickynote;
2 |
3 | import com.feiniaojin.ddd.aigc.application.service.stickynote.dto.*;
4 | import com.feiniaojin.ddd.aigc.domain.*;
5 | import jakarta.annotation.Resource;
6 | import org.springframework.stereotype.Service;
7 |
8 | import java.util.Arrays;
9 | import java.util.List;
10 |
11 |
12 | @Service
13 | public class StickyNoteCommandApplicationService {
14 |
15 | @Resource
16 | private StickyNoteEntityFactory factory;
17 |
18 | @Resource
19 | private StickyNoteEntityRepository repository;
20 |
21 | public StickyNoteCreateView createStickyNote(StickyNoteCreateCommand command) {
22 |
23 | String string = command.getParticipants();
24 | List list = Arrays.stream(string.split(",")).toList();
25 |
26 | StickyNoteEntity entity = factory.newInstance(command.getUid(),
27 | command.getDiaryId(),
28 | command.getContent(),
29 | list,
30 | command.getOccurrenceTimeStr());
31 |
32 | entity.completeCreate();
33 |
34 | repository.save(entity);
35 |
36 | return new StickyNoteCreateView(entity.getStickyNoteEntityId().getValue());
37 | }
38 |
39 | public void modifyStickyNote(StickyNoteModifyCommand command) {
40 |
41 | StickyNoteEntity entity = repository.load(new StickyNoteEntityId(command.getStickyNoteId()));
42 |
43 | entity.modify(command.getContent(), command.getParticipants());
44 |
45 | repository.save(entity);
46 | }
47 |
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/stickynote/StickyNoteEntityFactoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.stickynote;
2 |
3 | import com.feiniaojin.ddd.aigc.domain.DiaryEntityId;
4 | import com.feiniaojin.ddd.aigc.domain.StickyNoteEntity;
5 | import com.feiniaojin.ddd.aigc.domain.StickyNoteEntityFactory;
6 | import com.feiniaojin.ddd.aigc.domain.StickyNoteEntityId;
7 | import com.feiniaojin.ddd.aigc.infrastructure.persistence.data.Diary;
8 | import com.feiniaojin.ddd.aigc.infrastructure.persistence.jdbc.DiaryJdbcRepository;
9 | import jakarta.annotation.Resource;
10 | import org.apache.commons.lang3.RandomStringUtils;
11 | import org.apache.commons.lang3.StringUtils;
12 | import org.springframework.stereotype.Component;
13 |
14 | import java.text.DateFormat;
15 | import java.text.SimpleDateFormat;
16 | import java.util.Date;
17 | import java.util.List;
18 |
19 | @Component
20 | public class StickyNoteEntityFactoryImpl implements StickyNoteEntityFactory {
21 |
22 | @Resource
23 | private DiaryJdbcRepository diaryJdbcRepository;
24 |
25 | @Override
26 | public StickyNoteEntity newInstance(String uid, String diaryId, String content, List participants, String occurrenceTimeStr) {
27 |
28 | StickyNoteEntity entity = new StickyNoteEntity();
29 |
30 | String stickyNoteId = RandomStringUtils.randomAlphanumeric(9);
31 | entity.setStickyNoteEntityId(new StickyNoteEntityId(stickyNoteId));
32 | entity.setDiaryEntityId(new DiaryEntityId(diaryId));
33 | entity.setContent(content);
34 | entity.setParticipants(participants);
35 | entity.setUid(uid);
36 | if (StringUtils.isBlank(occurrenceTimeStr)) {
37 | throw new IllegalArgumentException();
38 | }
39 | Diary diary = diaryJdbcRepository.findByDiaryId(diaryId);
40 | try {
41 | occurrenceTimeStr = diary.getDiaryDateStr() + " " + occurrenceTimeStr;
42 | DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
43 | Date parse = dateFormat.parse(occurrenceTimeStr);
44 | entity.setOccurrenceTime(parse);
45 | } catch (Exception e) {
46 | throw new IllegalArgumentException();
47 | }
48 | entity.setDeleted(0);
49 |
50 | Date date = new Date();
51 | entity.setCreatedDate(date);
52 | entity.setLastModifiedDate(date);
53 |
54 | return entity;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/stickynote/StickyNoteQueryApplicationService.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.stickynote;
2 |
3 | import com.feiniaojin.ddd.aigc.application.service.stickynote.dto.StickyNoteGenerateContentQuery;
4 | import com.feiniaojin.ddd.aigc.application.service.stickynote.dto.StickyNoteGenerateContentView;
5 | import com.feiniaojin.ddd.aigc.application.service.stickynote.dto.StickyNoteQuery;
6 | import com.feiniaojin.ddd.aigc.application.service.stickynote.dto.StickyNoteView;
7 | import com.feiniaojin.ddd.aigc.domain.DiaryEntityId;
8 | import com.feiniaojin.ddd.aigc.domain.StickyNoteGenerateContentDomainService;
9 | import com.feiniaojin.ddd.aigc.infrastructure.gateway.LlmConfig;
10 | import com.feiniaojin.ddd.aigc.infrastructure.gateway.llm.LlmProvider;
11 | import com.feiniaojin.ddd.aigc.infrastructure.gateway.llm.LlmProviderRegister;
12 | import com.feiniaojin.ddd.aigc.infrastructure.persistence.data.StickyNote;
13 | import com.feiniaojin.ddd.aigc.infrastructure.persistence.jdbc.StickyNoteJdbcRepository;
14 | import com.feiniaojin.gracefulresponse.data.PageBean;
15 | import com.google.gson.Gson;
16 | import com.google.gson.reflect.TypeToken;
17 | import jakarta.annotation.Resource;
18 | import org.springframework.ai.chat.messages.Message;
19 | import org.springframework.ai.chat.messages.SystemMessage;
20 | import org.springframework.ai.chat.messages.UserMessage;
21 | import org.springframework.ai.chat.prompt.Prompt;
22 | import org.springframework.stereotype.Service;
23 | import org.springframework.util.CollectionUtils;
24 | import reactor.core.publisher.Flux;
25 |
26 | import java.text.DateFormat;
27 | import java.text.SimpleDateFormat;
28 | import java.util.ArrayList;
29 | import java.util.List;
30 |
31 |
32 | @Service
33 | public class StickyNoteQueryApplicationService {
34 |
35 | @Resource
36 | private StickyNoteGenerateContentDomainService generateContentDomainService;
37 |
38 | @Resource
39 | private StickyNoteJdbcRepository stickyNoteJdbcRepository;
40 |
41 | Gson gson = new Gson();
42 |
43 | @Resource
44 | private LlmProviderRegister llmProviderRegister;
45 |
46 | @Resource
47 | private LlmConfig llmConfig;
48 |
49 | private PageBean pageList(StickyNoteQuery query) {
50 |
51 | return null;
52 | }
53 |
54 | public StickyNoteGenerateContentView generateDiaryContent(StickyNoteGenerateContentQuery query) {
55 |
56 | String content = generateContentDomainService.generateContent(new DiaryEntityId(query.getDiaryId()), query.getUserInput());
57 |
58 | StickyNoteGenerateContentView view = new StickyNoteGenerateContentView();
59 | view.setGenerateContent(content);
60 |
61 | return view;
62 | }
63 |
64 | public Flux generateDiaryContentStream(StickyNoteGenerateContentQuery query) {
65 | String diaryId = query.getDiaryId();
66 | String uid = query.getUid();
67 | String conversationId = uid + diaryId;
68 | List messages = new ArrayList<>();
69 |
70 | //增加系统提示词
71 | SystemMessage systemMessage = new SystemMessage(llmConfig.getDefaultSystemMessage());
72 | messages.add(systemMessage);
73 | //简单处理,每次都查库,避免贴纸有新增
74 | List stickyNotes = stickyNoteJdbcRepository.queryListByDiaryId(diaryId);
75 | String content = noteContent(stickyNotes);
76 | String userInput = query.getUserInput();
77 | UserMessage userMessage = new UserMessage(content + userInput);
78 | messages.add(userMessage);
79 |
80 | String providerName = llmConfig.getProviderName();
81 | LlmProvider llmProvider = llmProviderRegister.getLlmProvider(providerName);
82 |
83 | Prompt prompt = new Prompt(messages);
84 | return llmProvider.generateContentStream(prompt, conversationId);
85 | }
86 |
87 | /**
88 | * 根据StickyNoteEntity生成内容
89 | *
90 | * @param stickyNoteEntities
91 | * @return
92 | */
93 | private String noteContent(List stickyNoteEntities) {
94 |
95 | DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
96 |
97 | StringBuilder stringBuilder = new StringBuilder();
98 |
99 | for (StickyNote note : stickyNoteEntities) {
100 | //08:00:00 和aaa、bbb一起,正文
101 | if (note.getOccurrenceTime() != null) {
102 | stringBuilder.append("时间:");
103 | stringBuilder.append(dateFormat.format(note.getOccurrenceTime()));
104 | stringBuilder.append(",");
105 | }
106 | String string = note.getParticipants();
107 | List participants = gson.fromJson(string, new TypeToken>() {
108 | }.getType());
109 | if (!CollectionUtils.isEmpty(participants)) {
110 | stringBuilder.append("参与者:");
111 | for (String p : participants) {
112 | stringBuilder.append(p);
113 | stringBuilder.append("、");
114 | }
115 | stringBuilder.deleteCharAt(stringBuilder.lastIndexOf("、"));
116 | stringBuilder.append(",");
117 | }
118 |
119 | //活动
120 | stringBuilder.append("活动:");
121 | stringBuilder.append(note.getContent());
122 | stringBuilder.append(";");
123 | }
124 | return stringBuilder.toString();
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/stickynote/dto/StickyNoteCreateCommand.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.stickynote.dto;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.List;
6 |
7 | @Data
8 | public class StickyNoteCreateCommand {
9 |
10 | private String uid;
11 |
12 | private String diaryId;
13 |
14 | private String content;
15 |
16 | private String participants;
17 |
18 | private String occurrenceTimeStr;
19 | }
20 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/stickynote/dto/StickyNoteCreateView.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.stickynote.dto;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.List;
6 |
7 | @Data
8 | public class StickyNoteCreateView {
9 |
10 | public StickyNoteCreateView(String stickyNoteId) {
11 | this.stickyNoteId = stickyNoteId;
12 | }
13 |
14 | private String stickyNoteId;
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/stickynote/dto/StickyNoteGenerateContentQuery.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.stickynote.dto;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class StickyNoteGenerateContentQuery {
7 |
8 | /**
9 | * 日志ID
10 | */
11 | private String diaryId;
12 |
13 | private String userInput;
14 |
15 | public String uid;
16 | }
17 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/stickynote/dto/StickyNoteGenerateContentView.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.stickynote.dto;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * 根据贴纸生成文本
7 | */
8 | @Data
9 | public class StickyNoteGenerateContentView {
10 | private String generateContent;
11 | }
12 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/stickynote/dto/StickyNoteModifyCommand.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.stickynote.dto;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.List;
6 |
7 | @Data
8 | public class StickyNoteModifyCommand {
9 |
10 | private String stickyNoteId;
11 |
12 | private String content;
13 |
14 | private List participants;
15 | }
16 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/stickynote/dto/StickyNoteQuery.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.stickynote.dto;
2 |
3 | public class StickyNoteQuery {
4 | }
5 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/java/com/feiniaojin/ddd/aigc/application/service/stickynote/dto/StickyNoteView.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.application.service.stickynote.dto;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * 创建成功后,需要回传ID
9 | */
10 | @Data
11 | public class StickyNoteView {
12 | private String uid;
13 |
14 | private String diaryId;
15 |
16 | private String content;
17 |
18 | private List participants;
19 |
20 | private String occurrenceTimeStr;
21 | }
22 |
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/main/resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-application-service/src/main/resources/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-application-service/src/test/java/com/feiniaojin/ddd/aigc/application/service/test/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-application-service/src/test/java/com/feiniaojin/ddd/aigc/application/service/test/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-domain/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ddd-aigc
6 | com.feiniaojin.ddd.aigc
7 | 1.0-SNAPSHOT
8 |
9 | 4.0.0
10 |
11 | ddd-aigc-domain
12 |
13 | 领域模型层,用于放置领域模型,包括实体、值对象、Repository、Factory等的定义
14 |
15 |
16 | 17
17 | 17
18 |
19 |
20 |
21 |
22 | org.projectlombok
23 | lombok
24 |
25 |
26 | org.apache.commons
27 | commons-lang3
28 |
29 |
30 | com.feiniaojin
31 | ddd
32 |
33 |
34 | org.mybatis.spring.boot
35 | mybatis-spring-boot-starter
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/ddd-aigc-domain/src/main/java/com/feiniaojin/ddd/aigc/domain/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-domain/src/main/java/com/feiniaojin/ddd/aigc/domain/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-domain/src/main/java/com/feiniaojin/ddd/aigc/domain/DiaryEntity.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.domain;
2 |
3 | import com.feiniaojin.ddd.AbstractDomainMask;
4 | import lombok.Data;
5 |
6 | import java.util.Date;
7 |
8 | /**
9 | * 一篇日记
10 | */
11 | @Data
12 | public class DiaryEntity extends AbstractDomainMask {
13 |
14 | /**
15 | * 日记id
16 | */
17 | private DiaryEntityId diaryEntityId;
18 |
19 | /**
20 | * 用户ID
21 | */
22 | private String uid;
23 |
24 | /**
25 | * 日记记录的那一天
26 | */
27 | private Date diaryDate;
28 |
29 | /**
30 | * 日记记录的那一天
31 | */
32 | private String diaryDateStr;
33 |
34 | /**
35 | * 根据白板生成的日记内容
36 | */
37 | private String content;
38 |
39 | public void create() {
40 |
41 | }
42 |
43 | public void modifyContent(String content) {
44 | this.content = content;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ddd-aigc-domain/src/main/java/com/feiniaojin/ddd/aigc/domain/DiaryEntityFactory.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.domain;
2 |
3 |
4 | public interface DiaryEntityFactory {
5 |
6 | /**
7 | * 创建新日记
8 | *
9 | * @param uid 用户id
10 | * @param diaryDate 日记当天
11 | * @return
12 | */
13 | DiaryEntity newInstance(String uid, String diaryDate);
14 | }
15 |
--------------------------------------------------------------------------------
/ddd-aigc-domain/src/main/java/com/feiniaojin/ddd/aigc/domain/DiaryEntityId.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.domain;
2 |
3 | import com.feiniaojin.ddd.AbstractEntityId;
4 |
5 | public class DiaryEntityId extends AbstractEntityId {
6 |
7 | public DiaryEntityId(String value) {
8 | super(value);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/ddd-aigc-domain/src/main/java/com/feiniaojin/ddd/aigc/domain/DiaryEntityRepository.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.domain;
2 |
3 | import com.feiniaojin.ddd.DomainRepository;
4 |
5 | public interface DiaryEntityRepository extends DomainRepository {
6 | }
7 |
--------------------------------------------------------------------------------
/ddd-aigc-domain/src/main/java/com/feiniaojin/ddd/aigc/domain/LlmGateway.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.domain;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * 大模型调用网关
7 | */
8 | public interface LlmGateway {
9 |
10 | String generateContent(List stickyNoteEntities, String userInput);
11 | }
12 |
--------------------------------------------------------------------------------
/ddd-aigc-domain/src/main/java/com/feiniaojin/ddd/aigc/domain/StickyNoteEntity.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.domain;
2 |
3 | import com.feiniaojin.ddd.AbstractDomainMask;
4 | import lombok.Data;
5 |
6 | import java.util.Date;
7 | import java.util.List;
8 |
9 | /**
10 | * 便利贴
11 | */
12 | @Data
13 | public class StickyNoteEntity extends AbstractDomainMask {
14 |
15 | /**
16 | * 便利贴ID
17 | */
18 | private StickyNoteEntityId stickyNoteEntityId;
19 |
20 |
21 | /**
22 | * 日记ID
23 | */
24 | private DiaryEntityId diaryEntityId;
25 |
26 | /**
27 | * 贴纸正文
28 | */
29 | private String content;
30 |
31 | /**
32 | * 用户id
33 | */
34 | private String uid;
35 |
36 | /**
37 | * 参与者
38 | */
39 | private List participants;
40 |
41 | /**
42 | * 贴纸对应的发生时间
43 | * 2023-01-01 08:00:00
44 | */
45 | private Date occurrenceTime;
46 |
47 | /**
48 | * 修改贴纸信息
49 | *
50 | * @param content
51 | * @param participants
52 | */
53 | public void modify(String content, List participants) {
54 | this.content = content;
55 | this.participants = participants;
56 | }
57 |
58 | /**
59 | * 创建贴纸
60 | */
61 | public void completeCreate() {
62 |
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/ddd-aigc-domain/src/main/java/com/feiniaojin/ddd/aigc/domain/StickyNoteEntityFactory.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.domain;
2 |
3 | import java.util.List;
4 |
5 | public interface StickyNoteEntityFactory {
6 |
7 |
8 | /**
9 | * 创建贴纸
10 | *
11 | * @param uid 用户ID
12 | * @param diaryId 日记ID
13 | * @param content 正文内容
14 | * @param participants 参与者
15 | * @return
16 | */
17 | StickyNoteEntity newInstance(String uid, String diaryId, String content, List participants, String occurrenceTimeStr);
18 | }
19 |
--------------------------------------------------------------------------------
/ddd-aigc-domain/src/main/java/com/feiniaojin/ddd/aigc/domain/StickyNoteEntityId.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.domain;
2 |
3 | import com.feiniaojin.ddd.AbstractEntityId;
4 |
5 | /**
6 | * 便利贴ID
7 | */
8 | public class StickyNoteEntityId extends AbstractEntityId {
9 |
10 | public StickyNoteEntityId(String value) {
11 | super(value);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ddd-aigc-domain/src/main/java/com/feiniaojin/ddd/aigc/domain/StickyNoteEntityRepository.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.domain;
2 |
3 | import com.feiniaojin.ddd.DomainRepository;
4 |
5 | public interface StickyNoteEntityRepository extends DomainRepository {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/ddd-aigc-domain/src/main/java/com/feiniaojin/ddd/aigc/domain/StickyNoteGenerateContentDomainService.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.domain;
2 |
3 | /**
4 | * 根据贴纸生成文本的领域服务
5 | * 要根据日记下的多个StickyNote聚合生成文本,因此是一个领域服务
6 | */
7 | public interface StickyNoteGenerateContentDomainService {
8 |
9 | String generateContent(DiaryEntityId diaryEntityId, String userInput);
10 | }
11 |
--------------------------------------------------------------------------------
/ddd-aigc-domain/src/test/java/com/feiniaojin/ddd/aigc/domain/test/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-domain/src/test/java/com/feiniaojin/ddd/aigc/domain/test/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-frontend/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto eol=lf
2 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | .DS_Store
12 | dist
13 | dist-ssr
14 | coverage
15 | *.local
16 |
17 | /cypress/videos/
18 | /cypress/screenshots/
19 |
20 | # Editor directories and files
21 | .vscode/*
22 | !.vscode/extensions.json
23 | .idea
24 | *.suo
25 | *.ntvs*
26 | *.njsproj
27 | *.sln
28 | *.sw?
29 |
30 | *.tsbuildinfo
31 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/prettierrc",
3 | "semi": false,
4 | "singleQuote": true,
5 | "printWidth": 100
6 | }
7 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/README.md:
--------------------------------------------------------------------------------
1 | # ddd-aigc-frontend
2 |
3 | This template should help get you started developing with Vue 3 in Vite.
4 |
5 | ## Recommended IDE Setup
6 |
7 | [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
8 |
9 | ## Customize configuration
10 |
11 | See [Vite Configuration Reference](https://vite.dev/config/).
12 |
13 | ## Project Setup
14 |
15 | ```sh
16 | npm install
17 | ```
18 |
19 | ### Compile and Hot-Reload for Development
20 |
21 | ```sh
22 | npm run dev
23 | ```
24 |
25 | ### Compile and Minify for Production
26 |
27 | ```sh
28 | npm run build
29 | ```
30 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite App
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "paths": {
4 | "@/*": ["./src/*"]
5 | }
6 | },
7 | "exclude": ["node_modules", "dist"]
8 | }
9 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ddd-aigc-frontend",
3 | "version": "0.0.0",
4 | "private": true,
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview",
10 | "format": "prettier --write src/"
11 | },
12 | "dependencies": {
13 | "axios": "^1.8.3",
14 | "element-plus": "^2.9.6",
15 | "pinia": "^3.0.1",
16 | "pinia-plugin-persistedstate": "^4.2.0",
17 | "vue": "^3.5.13",
18 | "vue-axios": "^3.5.2",
19 | "vue-router": "^4.5.0",
20 | "vuedraggable": "^4.1.0"
21 | },
22 | "devDependencies": {
23 | "@vitejs/plugin-vue": "^5.2.1",
24 | "prettier": "3.5.3",
25 | "vite": "^6.2.1",
26 | "vite-plugin-vue-devtools": "^7.7.2"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-frontend/public/favicon.ico
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
27 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/api/diary.js:
--------------------------------------------------------------------------------
1 | import request from "@/utils/request";
2 |
3 | export function createDiary(data) {
4 | return request({
5 | url: "/diary/create",
6 | method: "POST",
7 | data,
8 | });
9 | }
10 |
11 | export function saveContent(data) {
12 | return request({
13 | url: "/diary/saveContent",
14 | method: "POST",
15 | data,
16 | });
17 | }
18 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/api/stickynote.js:
--------------------------------------------------------------------------------
1 | import request from "@/utils/request";
2 |
3 | export function createStickyNote(data) {
4 | return request({
5 | url: "/stickyNote/create",
6 | method: "POST",
7 | data,
8 | });
9 | }
10 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/assets/base.css:
--------------------------------------------------------------------------------
1 | /* color palette from */
2 | :root {
3 | --vt-c-white: #ffffff;
4 | --vt-c-white-soft: #f8f8f8;
5 | --vt-c-white-mute: #f2f2f2;
6 |
7 | --vt-c-black: #181818;
8 | --vt-c-black-soft: #222222;
9 | --vt-c-black-mute: #282828;
10 |
11 | --vt-c-indigo: #2c3e50;
12 |
13 | --vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
14 | --vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
15 | --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
16 | --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
17 |
18 | --vt-c-text-light-1: var(--vt-c-indigo);
19 | --vt-c-text-light-2: rgba(60, 60, 60, 0.66);
20 | --vt-c-text-dark-1: var(--vt-c-white);
21 | --vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
22 | }
23 |
24 | /* semantic color variables for this project */
25 | :root {
26 | --color-background: var(--vt-c-white);
27 | --color-background-soft: var(--vt-c-white-soft);
28 | --color-background-mute: var(--vt-c-white-mute);
29 |
30 | --color-border: var(--vt-c-divider-light-2);
31 | --color-border-hover: var(--vt-c-divider-light-1);
32 |
33 | --color-heading: var(--vt-c-text-light-1);
34 | --color-text: var(--vt-c-text-light-1);
35 |
36 | --section-gap: 160px;
37 | }
38 |
39 | @media (prefers-color-scheme: dark) {
40 | :root {
41 | --color-background: var(--vt-c-black);
42 | --color-background-soft: var(--vt-c-black-soft);
43 | --color-background-mute: var(--vt-c-black-mute);
44 |
45 | --color-border: var(--vt-c-divider-dark-2);
46 | --color-border-hover: var(--vt-c-divider-dark-1);
47 |
48 | --color-heading: var(--vt-c-text-dark-1);
49 | --color-text: var(--vt-c-text-dark-2);
50 | }
51 | }
52 |
53 | *,
54 | *::before,
55 | *::after {
56 | box-sizing: border-box;
57 | margin: 0;
58 | font-weight: normal;
59 | }
60 |
61 | body {
62 | min-height: 100vh;
63 | color: var(--color-text);
64 | background: var(--color-background);
65 | transition:
66 | color 0.5s,
67 | background-color 0.5s;
68 | line-height: 1.6;
69 | font-family:
70 | Inter,
71 | -apple-system,
72 | BlinkMacSystemFont,
73 | 'Segoe UI',
74 | Roboto,
75 | Oxygen,
76 | Ubuntu,
77 | Cantarell,
78 | 'Fira Sans',
79 | 'Droid Sans',
80 | 'Helvetica Neue',
81 | sans-serif;
82 | font-size: 15px;
83 | text-rendering: optimizeLegibility;
84 | -webkit-font-smoothing: antialiased;
85 | -moz-osx-font-smoothing: grayscale;
86 | }
87 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/assets/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/assets/main.css:
--------------------------------------------------------------------------------
1 | @import './base.css';
2 |
3 | #app {
4 | max-width: 1280px;
5 | margin: 0 auto;
6 | padding: 2rem;
7 | font-weight: normal;
8 | }
9 |
10 | a,
11 | .green {
12 | text-decoration: none;
13 | color: hsla(160, 100%, 37%, 1);
14 | transition: 0.4s;
15 | padding: 3px;
16 | }
17 |
18 | @media (hover: hover) {
19 | a:hover {
20 | background-color: hsla(160, 100%, 37%, 0.2);
21 | }
22 | }
23 |
24 | @media (min-width: 1024px) {
25 | body {
26 | display: flex;
27 | place-items: center;
28 | }
29 |
30 | #app {
31 | display: grid;
32 | grid-template-columns: 1fr 1fr;
33 | padding: 0 2rem;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
{{ msg }}
13 |
14 | You’ve successfully created a project with
15 | Vite +
16 | Vue 3 .
17 |
18 |
19 |
20 |
21 |
45 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/components/TheWelcome.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Documentation
18 |
19 | Vue’s
20 | official documentation
21 | provides you with all information you need to get started.
22 |
23 |
24 |
25 |
26 |
27 |
28 | Tooling
29 |
30 | This project is served and bundled with
31 | Vite . The
32 | recommended IDE setup is
33 | VSCode
34 | +
35 | Volar . If
36 | you need to test your components and web pages, check out
37 | Vitest
38 | and
39 | Cypress
40 | /
41 | Playwright .
42 |
43 |
44 |
45 | More instructions are available in
46 | README.md
.
48 |
49 |
50 |
51 |
52 |
53 |
54 | Ecosystem
55 |
56 | Get official tools and libraries for your project:
57 | Pinia ,
58 | Vue Router ,
59 | Vue Test Utils , and
60 | Vue Dev Tools . If
61 | you need more resources, we suggest paying
62 | Awesome Vue
63 | a visit.
64 |
65 |
66 |
67 |
68 |
69 |
70 | Community
71 |
72 | Got stuck? Ask your question on
73 | Vue Land
74 | (our official Discord server), or
75 | StackOverflow . You should also follow the official
78 | @vuejs.org
79 | Bluesky account or the
80 | @vuejs
81 | X account for latest news in the Vue world.
82 |
83 |
84 |
85 |
86 |
87 |
88 | Support Vue
89 |
90 | As an independent project, Vue relies on community backing for its sustainability. You can help
91 | us by
92 | becoming a sponsor .
93 |
94 |
95 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/components/WelcomeItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
87 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/components/icons/IconCommunity.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/components/icons/IconDocumentation.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/components/icons/IconEcosystem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/components/icons/IconSupport.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/components/icons/IconTooling.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 | import ElementPlus from 'element-plus'
5 | import 'element-plus/dist/index.css'
6 | import axios from "axios";
7 | import VueAxios from "vue-axios"
8 | import { createPinia } from 'pinia'
9 | import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
10 |
11 | const pinia = createPinia()
12 | pinia.use(piniaPluginPersistedstate);
13 |
14 | const app = createApp(App)
15 | app.use(router)
16 | app.use(ElementPlus)
17 | app.use(VueAxios, axios); // 挂载到全局
18 | app.use(pinia)
19 | app.mount('#app')
20 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/router/index.js:
--------------------------------------------------------------------------------
1 | import {createRouter, createWebHistory} from 'vue-router'
2 | import BasicInfo from '../views/BasicInfo.vue'
3 | import WhiteBoard from '../views/WhiteBoard.vue'
4 | import Content from '../views/Content.vue'
5 |
6 | const routes = [
7 | {
8 | path: '/basic',
9 | name: 'basic',
10 | component: BasicInfo
11 | },
12 | {
13 | path: '/whiteBoard',
14 | name: 'home',
15 | component: WhiteBoard
16 | },
17 | {
18 | path: '/content',
19 | name: 'content',
20 | component: Content
21 | }
22 | ]
23 |
24 | const router = createRouter({
25 | history: createWebHistory(),
26 | routes
27 | })
28 |
29 | export default router
30 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/store/info.js:
--------------------------------------------------------------------------------
1 | // store/info.js
2 | import { defineStore } from 'pinia';
3 | import storage from '@/utils/storage';
4 |
5 | export const useInfoStore = defineStore('info', {
6 | state: () => ({
7 | uid: storage.get('uid') || '',
8 | diary: storage.get('diary') || null
9 | }),
10 | actions: {
11 | setUid(uid) {
12 | this.uid = uid;
13 | storage.set('uid', uid);
14 | },
15 | setDiary(diary) {
16 | this.diary = diary;
17 | storage.set('diary', diary);
18 | },
19 | clearInfo() {
20 | this.uid = '';
21 | this.diary = null;
22 | storage.remove('uid');
23 | storage.remove('diary'); // 注意:原代码错误地移除了 'user'
24 | }
25 | },
26 | persist: true
27 | });
28 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/utils/request.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | // 创建 Axios 实例
4 | const service = axios.create({
5 | baseURL: "http://localhost:5173/api/", // 接口基础路径
6 | timeout: 500000, // 超时时间,调试方便,搞长点
7 | });
8 |
9 | // 请求拦截器
10 | service.interceptors.request.use(
11 | (config) => {
12 | // 可在此处添加 token(示例)
13 | const token = localStorage.getItem("token");
14 | if (token) {
15 | config.headers.Authorization = `Bearer ${token}`;
16 | }
17 | return config;
18 | },
19 | (error) => {
20 | return Promise.reject(error);
21 | }
22 | );
23 |
24 | // 响应拦截器
25 | service.interceptors.response.use(
26 | (response) => {
27 | // 统一处理响应数据格式
28 | const res = response.data;
29 | if (res.code != 0) {
30 | alert(res.message || "请求失败");
31 | return Promise.reject(res);
32 | }
33 | return res;
34 | },
35 | (error) => {
36 | alert("网络错误");
37 | return Promise.reject(error);
38 | }
39 | );
40 |
41 | export default service;
42 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/utils/storage.js:
--------------------------------------------------------------------------------
1 | // 存储工具 utils/storage.js (保持原样)
2 | export default {
3 | set(key, value) {
4 | localStorage.setItem(key, JSON.stringify(value));
5 | },
6 | get(key) {
7 | const value = localStorage.getItem(key);
8 | return value ? JSON.parse(value) : null;
9 | },
10 | remove(key) {
11 | localStorage.removeItem(key);
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/views/AboutView.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
This is an about page
4 |
5 |
6 |
7 |
16 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/views/BasicInfo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
17 |
18 |
19 |
20 | Create
21 | Cancel
22 |
23 |
24 |
25 |
26 |
60 |
63 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/views/Content.vue:
--------------------------------------------------------------------------------
1 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | 当前用户:
63 |
64 |
65 |
66 | 日记ID:
67 |
68 |
69 |
70 |
71 |
72 |
78 |
79 |
80 |
86 | 生成
87 | 保存
88 |
89 |
90 |
91 |
92 |
95 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/views/HomeView.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/src/views/WhiteBoard.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
{{ sticker.participants }}
16 |
{{ sticker.event }}
17 |
18 |
19 |
20 |
21 |
31 |
32 |
33 |
38 |
39 |
40 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | 取消
56 | 确定
57 |
58 |
59 |
60 |
61 |
62 |
132 |
133 |
197 |
--------------------------------------------------------------------------------
/ddd-aigc-frontend/vite.config.js:
--------------------------------------------------------------------------------
1 | import { fileURLToPath, URL } from 'node:url'
2 |
3 | import { defineConfig } from 'vite'
4 | import vue from '@vitejs/plugin-vue'
5 | import vueDevTools from 'vite-plugin-vue-devtools'
6 |
7 | // https://vite.dev/config/
8 | export default defineConfig({
9 | plugins: [
10 | vue(),
11 | vueDevTools(),
12 | ],
13 | resolve: {
14 | alias: {
15 | '@': fileURLToPath(new URL('./src', import.meta.url))
16 | },
17 | },
18 | server:{
19 | proxy: {
20 | '/api': { // 代理路径前缀(根据业务命名)
21 | target: 'http://localhost:9899', // 目标服务器地址
22 | changeOrigin: true, // 修改请求头中的 Origin 为目标域名
23 | rewrite: (path) => path.replace(/^\/api/, '') // 路径重写(可选)
24 | }
25 | }
26 | }
27 | })
28 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-cache/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | com.feiniaojin.ddd.aigc
6 | ddd-aigc
7 | 1.0-SNAPSHOT
8 |
9 |
10 | ddd-aigc-infrastructure-cache
11 |
12 |
13 | 8
14 | 8
15 | UTF-8
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-cache/src/main/java/com/feiniaojin/Main.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin;
2 |
3 | // Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
4 | // then press Enter. You can now see whitespace characters in your code.
5 | public class Main {
6 | public static void main(String[] args) {
7 | // Press Opt+Enter with your caret at the highlighted text to see how
8 | // IntelliJ IDEA suggests fixing it.
9 | System.out.printf("Hello and welcome!");
10 |
11 | // Press Ctrl+R or click the green arrow button in the gutter to run the code.
12 | for (int i = 1; i <= 5; i++) {
13 |
14 | // Press Ctrl+D to start debugging your code. We have set one breakpoint
15 | // for you, but you can always add more by pressing Cmd+F8.
16 | System.out.println("i = " + i);
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-gateway/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ddd-aigc
6 | com.feiniaojin.ddd.aigc
7 | 1.0-SNAPSHOT
8 |
9 | 4.0.0
10 |
11 | ddd-aigc-infrastructure-gateway
12 |
13 |
14 | 8
15 | 8
16 |
17 |
18 |
19 |
20 | org.springframework.boot
21 | spring-boot
22 |
23 |
24 | org.springframework
25 | spring-beans
26 |
27 |
28 | org.springframework
29 | spring-context
30 |
31 |
32 | org.apache.commons
33 | commons-lang3
34 |
35 |
36 | org.projectlombok
37 | lombok
38 |
39 |
40 | com.feiniaojin.ddd.aigc
41 | ddd-aigc-domain
42 |
43 |
44 | com.theokanning.openai-gpt3-java
45 | api
46 |
47 |
48 | com.theokanning.openai-gpt3-java
49 | client
50 |
51 |
52 | com.theokanning.openai-gpt3-java
53 | service
54 |
55 |
56 | org.springframework.ai
57 | spring-ai-ollama-spring-boot-starter
58 |
59 |
60 | org.springframework.ai
61 | spring-ai-openai-spring-boot-starter
62 |
63 |
64 | org.springframework.boot
65 | spring-boot-starter-web
66 | 3.4.2
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-gateway/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/gateway/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-infrastructure-gateway/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/gateway/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-gateway/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/gateway/LlmConfig.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.gateway;
2 |
3 | import io.micrometer.observation.ObservationRegistry;
4 | import lombok.Data;
5 | import org.springframework.ai.chat.client.ChatClient;
6 | import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
7 | import org.springframework.ai.chat.memory.ChatMemory;
8 | import org.springframework.ai.chat.memory.InMemoryChatMemory;
9 | import org.springframework.ai.model.ApiKey;
10 | import org.springframework.ai.model.SimpleApiKey;
11 | import org.springframework.ai.model.tool.DefaultToolCallingManager;
12 | import org.springframework.ai.ollama.OllamaChatModel;
13 | import org.springframework.ai.ollama.api.OllamaApi;
14 | import org.springframework.ai.ollama.api.OllamaOptions;
15 | import org.springframework.ai.ollama.management.ModelManagementOptions;
16 | import org.springframework.ai.openai.OpenAiChatModel;
17 | import org.springframework.ai.openai.OpenAiChatOptions;
18 | import org.springframework.ai.openai.api.OpenAiApi;
19 | import org.springframework.ai.retry.RetryUtils;
20 | import org.springframework.beans.factory.annotation.Value;
21 | import org.springframework.boot.context.properties.ConfigurationProperties;
22 | import org.springframework.context.annotation.Bean;
23 | import org.springframework.context.annotation.Configuration;
24 | import org.springframework.util.CollectionUtils;
25 | import org.springframework.web.client.RestClient;
26 | import org.springframework.web.reactive.function.client.WebClient;
27 |
28 | import java.util.Map;
29 |
30 | @Configuration
31 | @ConfigurationProperties(prefix = "ddd-aigc")
32 | @Data
33 | public class LlmConfig {
34 |
35 | private String providerName;
36 |
37 | private String defaultSystemMessage;
38 |
39 | // DeepSeek官网
40 | @Bean
41 | public ChatClient deepSeekOfficialClient(@Value("${spring.ai.providers.deepseek-official.base-url}") String baseUrl,
42 | @Value("${spring.ai.providers.deepseek-official.api-key}") String apiKey,
43 | @Value("${spring.ai.providers.deepseek-official.model}") String model,
44 | ChatMemory chatMemory) {
45 |
46 | ApiKey apiKey1 = (new SimpleApiKey(apiKey));
47 |
48 | OpenAiApi openAiApi = new OpenAiApi(baseUrl, apiKey1, CollectionUtils.toMultiValueMap(Map.of()),
49 | "/chat/completions", "/embeddings",
50 | RestClient.builder(), WebClient.builder(), RetryUtils.DEFAULT_RESPONSE_ERROR_HANDLER);
51 |
52 | OpenAiChatOptions openAiChatOptions = OpenAiChatOptions.builder().model(model).build();
53 |
54 | DefaultToolCallingManager callingManager = DefaultToolCallingManager.builder().build();
55 |
56 | OpenAiChatModel openAiChatModel = new OpenAiChatModel(openAiApi, openAiChatOptions, callingManager, RetryUtils.DEFAULT_RETRY_TEMPLATE, ObservationRegistry.NOOP);
57 |
58 | return ChatClient.builder(openAiChatModel).defaultOptions(openAiChatOptions)
59 | .defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory)).build();
60 | }
61 |
62 | //硅基流动
63 | @Bean
64 | public ChatClient siliconflowClient(@Value("${spring.ai.providers.siliconflow.base-url}") String baseUrl,
65 | @Value("${spring.ai.providers.siliconflow.api-key}") String apiKey,
66 | @Value("${spring.ai.providers.siliconflow.model}") String model,
67 | ChatMemory chatMemory) {
68 | ApiKey apiKey1 = (new SimpleApiKey(apiKey));
69 |
70 | OpenAiApi openAiApi = new OpenAiApi(baseUrl, apiKey1, CollectionUtils.toMultiValueMap(Map.of()),
71 | "/chat/completions", "/embeddings",
72 | RestClient.builder(), WebClient.builder(), RetryUtils.DEFAULT_RESPONSE_ERROR_HANDLER);
73 |
74 | OpenAiChatOptions openAiChatOptions = OpenAiChatOptions.builder().model(model).build();
75 |
76 | DefaultToolCallingManager callingManager = DefaultToolCallingManager.builder().build();
77 |
78 | OpenAiChatModel openAiChatModel = new OpenAiChatModel(openAiApi, openAiChatOptions, callingManager, RetryUtils.DEFAULT_RETRY_TEMPLATE, ObservationRegistry.NOOP);
79 |
80 | return ChatClient.builder(openAiChatModel)
81 | .defaultOptions(openAiChatOptions)
82 | .defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory)).build();
83 | }
84 |
85 |
86 | //OpenAI配置
87 | @Bean
88 | public ChatClient openAIClient(@Value("${spring.ai.providers.openai.base-url}") String baseUrl,
89 | @Value("${spring.ai.providers.openai.api-key}") String apiKey,
90 | @Value("${spring.ai.providers.openai.model}") String model,
91 | ChatMemory chatMemory) {
92 | ApiKey apiKey1 = new SimpleApiKey(apiKey);
93 |
94 | OpenAiApi openAiApi = new OpenAiApi(baseUrl, apiKey1, CollectionUtils.toMultiValueMap(Map.of()),
95 | "/chat/completions", "/embeddings",
96 | RestClient.builder(), WebClient.builder(), RetryUtils.DEFAULT_RESPONSE_ERROR_HANDLER);
97 |
98 | OpenAiChatOptions openAiChatOptions = OpenAiChatOptions.builder().model(model).build();
99 |
100 | DefaultToolCallingManager callingManager = DefaultToolCallingManager.builder().build();
101 |
102 | OpenAiChatModel openAiChatModel = new OpenAiChatModel(openAiApi, openAiChatOptions, callingManager, RetryUtils.DEFAULT_RETRY_TEMPLATE, ObservationRegistry.NOOP);
103 |
104 | return ChatClient.builder(openAiChatModel)
105 | .defaultOptions(openAiChatOptions)
106 | .defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory)).build();
107 | }
108 |
109 | // Ollama本地部署配置
110 | @Bean
111 | public ChatClient ollamaClient(@Value("${spring.ai.providers.ollama.base-url}") String baseUrl,
112 | @Value("${spring.ai.providers.ollama.model}") String model,
113 | ChatMemory chatMemory) {
114 |
115 | OllamaApi ollamaApi = new OllamaApi(baseUrl);
116 |
117 | OllamaOptions ollamaOptions = OllamaOptions.builder().model(model).build();
118 |
119 | DefaultToolCallingManager callingManager = DefaultToolCallingManager.builder().build();
120 |
121 | OllamaChatModel ollamaChatModel = OllamaChatModel.builder()
122 | .ollamaApi(ollamaApi)
123 | .defaultOptions(ollamaOptions)
124 | .toolCallingManager(callingManager)
125 | .modelManagementOptions(ModelManagementOptions.defaults())
126 | .build();
127 |
128 | return ChatClient.builder(ollamaChatModel)
129 | .defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory)).build();
130 | }
131 |
132 | /**
133 | * Spring AI 提到不是所有的大模型都支持
134 | *
135 | * @return
136 | */
137 | @Bean
138 | public ChatMemory chatMemory() {
139 | return new InMemoryChatMemory();
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-gateway/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/gateway/LlmGatewayImpl.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.gateway;
2 |
3 | import com.feiniaojin.ddd.aigc.domain.LlmGateway;
4 | import com.feiniaojin.ddd.aigc.domain.StickyNoteEntity;
5 | import com.feiniaojin.ddd.aigc.infrastructure.gateway.llm.LlmProvider;
6 | import com.feiniaojin.ddd.aigc.infrastructure.gateway.llm.LlmProviderRegister;
7 | import jakarta.annotation.Resource;
8 | import org.apache.commons.lang3.StringUtils;
9 | import org.springframework.ai.chat.memory.ChatMemory;
10 | import org.springframework.ai.chat.messages.Message;
11 | import org.springframework.ai.chat.messages.SystemMessage;
12 | import org.springframework.ai.chat.messages.UserMessage;
13 | import org.springframework.ai.chat.prompt.Prompt;
14 | import org.springframework.stereotype.Component;
15 | import org.springframework.util.CollectionUtils;
16 |
17 | import java.text.DateFormat;
18 | import java.text.SimpleDateFormat;
19 | import java.util.ArrayList;
20 | import java.util.List;
21 |
22 | /**
23 | * ai调用网关
24 | */
25 | @Component
26 | public class LlmGatewayImpl implements LlmGateway {
27 |
28 | @Resource
29 | private LlmProviderRegister llmProviderRegister;
30 |
31 | @Resource
32 | private LlmConfig llmConfig;
33 |
34 | @Override
35 | public String generateContent(List stickyNoteEntities, String userInput) {
36 | StickyNoteEntity note = stickyNoteEntities.get(0);
37 | String uid = note.getUid();
38 | String diaryId = note.getDiaryEntityId().getValue();
39 |
40 | String conversationId = uid + diaryId;
41 | List messages = new ArrayList<>();
42 |
43 | //增加系统提示词,每次都提供
44 | SystemMessage systemMessage = new SystemMessage(llmConfig.getDefaultSystemMessage());
45 | messages.add(systemMessage);
46 |
47 | //简单处理,避免贴纸有新增
48 | String content = noteContent(stickyNoteEntities);
49 | UserMessage userMessage = new UserMessage(content + userInput);
50 | messages.add(userMessage);
51 |
52 | String providerName = llmConfig.getProviderName();
53 | LlmProvider llmProvider = llmProviderRegister.getLlmProvider(providerName);
54 | Prompt prompt = new Prompt(messages);
55 | return llmProvider.generateContent(prompt, conversationId);
56 | }
57 |
58 | /**
59 | * 根据StickyNoteEntity生成内容
60 | *
61 | * @param stickyNoteEntities
62 | * @return
63 | */
64 | private String noteContent(List stickyNoteEntities) {
65 |
66 | DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
67 |
68 | StringBuilder stringBuilder = new StringBuilder();
69 |
70 | for (StickyNoteEntity note : stickyNoteEntities) {
71 | //08:00:00 和aaa、bbb一起,正文
72 | if (note.getOccurrenceTime() != null) {
73 | stringBuilder.append("时间:");
74 | stringBuilder.append(dateFormat.format(note.getOccurrenceTime()));
75 | stringBuilder.append(",");
76 | }
77 |
78 | List participants = note.getParticipants();
79 | if (!CollectionUtils.isEmpty(participants)) {
80 | stringBuilder.append("参与者:");
81 | for (String p : participants) {
82 | stringBuilder.append(p);
83 | stringBuilder.append("、");
84 | }
85 | stringBuilder.deleteCharAt(stringBuilder.lastIndexOf("、"));
86 | stringBuilder.append(",");
87 | }
88 |
89 | //活动
90 | stringBuilder.append("活动:");
91 | stringBuilder.append(note.getContent());
92 | stringBuilder.append(";");
93 | }
94 | return stringBuilder.toString();
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-gateway/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/gateway/llm/AbstractLlmProviderImpl.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.gateway.llm;
2 |
3 | import org.springframework.ai.chat.client.ChatClient;
4 | import org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor;
5 | import org.springframework.ai.chat.prompt.ChatOptions;
6 | import org.springframework.ai.chat.prompt.Prompt;
7 | import reactor.core.publisher.Flux;
8 |
9 | import java.util.Optional;
10 |
11 | /**
12 | * LlmProvider的抽象实现类
13 | * - 把ChatClient引入进来
14 | * - 使用模板方法设计模式,把生成内容的过程统一起来
15 | */
16 | public abstract class AbstractLlmProviderImpl implements LlmProvider {
17 |
18 | private final ChatClient chatClient;
19 |
20 | public AbstractLlmProviderImpl(ChatClient chatClient) {
21 | this.chatClient = chatClient;
22 | }
23 |
24 | @Override
25 | public String generateContent(Prompt prompt, String conversationId) {
26 | Optional runtimeOptions = runtimeOptions();
27 | ChatClient.ChatClientRequestSpec requestSpec = chatClient.prompt(prompt);
28 | runtimeOptions.ifPresent(requestSpec::options);
29 | requestSpec.advisors(advisor ->
30 | advisor.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, conversationId)
31 | );
32 | return requestSpec.call().content();
33 | }
34 |
35 | /**
36 | * 子类调整运行时ChatOptions
37 | *
38 | * @return Optional
39 | */
40 | protected Optional runtimeOptions() {
41 | return Optional.empty();
42 | }
43 |
44 | @Override
45 | public Flux generateContentStream(Prompt prompt, String conversationId) {
46 | Optional runtimeOptions = runtimeOptions();
47 | ChatClient.ChatClientRequestSpec requestSpec = chatClient.prompt(prompt);
48 | runtimeOptions.ifPresent(requestSpec::options);
49 | requestSpec.advisors(advisor ->
50 | advisor.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, conversationId)
51 | );
52 | return requestSpec.stream().content();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-gateway/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/gateway/llm/DeepSeekLlmProviderImpl.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.gateway.llm;
2 |
3 | import org.springframework.ai.chat.client.ChatClient;
4 | import org.springframework.stereotype.Component;
5 |
6 | @Component
7 | public class DeepSeekLlmProviderImpl extends AbstractLlmProviderImpl {
8 |
9 | public DeepSeekLlmProviderImpl(ChatClient deepSeekOfficialClient) {
10 | super(deepSeekOfficialClient);
11 | }
12 |
13 | @Override
14 | public String providerName() {
15 | return "deepseek-official";
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-gateway/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/gateway/llm/LlmProvider.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.gateway.llm;
2 |
3 | import org.springframework.ai.chat.prompt.Prompt;
4 | import reactor.core.publisher.Flux;
5 |
6 | /**
7 | * 大语言模型提供者的抽象
8 | */
9 | public interface LlmProvider {
10 |
11 | String providerName();
12 |
13 | String generateContent(Prompt prompt, String conversationId);
14 |
15 | default Flux generateContentStream(Prompt prompt, String conversationId) {
16 | throw new UnsupportedOperationException("待实现");
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-gateway/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/gateway/llm/LlmProviderRegister.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.gateway.llm;
2 |
3 | import org.springframework.beans.BeansException;
4 | import org.springframework.context.ApplicationContext;
5 | import org.springframework.context.ApplicationContextAware;
6 | import org.springframework.stereotype.Component;
7 |
8 | import java.util.concurrent.ConcurrentHashMap;
9 |
10 | /**
11 | * 大语言模型提供者的抽象
12 | */
13 | @Component
14 | public class LlmProviderRegister implements ApplicationContextAware {
15 |
16 | private final ConcurrentHashMap providerMap = new ConcurrentHashMap<>();
17 |
18 | @Override
19 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
20 | applicationContext.getBeansOfType(LlmProvider.class).forEach((key, value) -> {
21 | providerMap.putIfAbsent(value.providerName(), value);
22 | });
23 | }
24 |
25 | public LlmProvider getLlmProvider(String providerName) {
26 | return providerMap.get(providerName);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-gateway/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/gateway/llm/OllamaLlmProviderImpl.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.gateway.llm;
2 |
3 | import org.springframework.ai.chat.client.ChatClient;
4 | import org.springframework.ai.chat.prompt.ChatOptions;
5 | import org.springframework.beans.factory.annotation.Value;
6 | import org.springframework.stereotype.Component;
7 |
8 | import java.util.Optional;
9 |
10 | @Component
11 | public class OllamaLlmProviderImpl extends AbstractLlmProviderImpl {
12 |
13 | /**
14 | * 运行时修改模型
15 | */
16 | @Value("${spring.ai.providers.ollama.model}")
17 | private String model;
18 |
19 | public OllamaLlmProviderImpl(ChatClient ollamaClient) {
20 | super(ollamaClient);
21 | }
22 |
23 | @Override
24 | protected Optional runtimeOptions() {
25 | return Optional.of(ChatOptions.builder().model(model).build());
26 | }
27 |
28 | @Override
29 | public String providerName() {
30 | return "ollama";
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-gateway/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/gateway/llm/OpenAiLlmProviderImpl.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.gateway.llm;
2 |
3 | import org.springframework.ai.chat.client.ChatClient;
4 | import org.springframework.stereotype.Component;
5 |
6 | @Component
7 | public class OpenAiLlmProviderImpl extends AbstractLlmProviderImpl {
8 |
9 | public OpenAiLlmProviderImpl(ChatClient openAIClient) {
10 | super(openAIClient);
11 | }
12 |
13 | @Override
14 | public String providerName() {
15 | return "openai";
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-gateway/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/gateway/llm/SiliconflowLlmProviderImpl.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.gateway.llm;
2 |
3 | import org.springframework.ai.chat.client.ChatClient;
4 | import org.springframework.stereotype.Component;
5 |
6 | @Component
7 | public class SiliconflowLlmProviderImpl extends AbstractLlmProviderImpl {
8 |
9 | public SiliconflowLlmProviderImpl(ChatClient siliconflowClient) {
10 | super(siliconflowClient);
11 | }
12 |
13 | @Override
14 | public String providerName() {
15 | return "siliconflow";
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-gateway/src/main/resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-infrastructure-gateway/src/main/resources/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-gateway/src/test/java/com/feiniaojin/ddd/aigc/infrastructure/gateway/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-infrastructure-gateway/src/test/java/com/feiniaojin/ddd/aigc/infrastructure/gateway/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-gateway/src/test/resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-infrastructure-gateway/src/test/resources/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-persistence/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ddd-aigc
5 | com.feiniaojin.ddd.aigc
6 | 1.0-SNAPSHOT
7 |
8 | 4.0.0
9 |
10 | ddd-aigc-infrastructure-persistence
11 |
12 |
13 | 17
14 | 17
15 |
16 |
17 |
18 |
19 | com.google.code.gson
20 | gson
21 |
22 |
23 | org.projectlombok
24 | lombok
25 |
26 |
27 | com.feiniaojin.ddd.aigc
28 | ddd-aigc-domain
29 |
30 |
31 | com.fasterxml.jackson.core
32 | jackson-core
33 |
34 |
35 | com.fasterxml.jackson.core
36 | jackson-databind
37 |
38 |
39 | com.fasterxml.jackson.core
40 | jackson-annotations
41 |
42 |
43 | org.springframework
44 | spring-context
45 |
46 |
47 | org.springframework
48 | spring-beans
49 |
50 |
51 | org.projectlombok
52 | lombok
53 |
54 |
55 | org.springframework.boot
56 | spring-boot-starter-data-jdbc
57 | 2.7.15
58 |
59 |
60 | com.mysql
61 | mysql-connector-j
62 | 8.0.33
63 | runtime
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-persistence/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/persistence/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-infrastructure-persistence/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/persistence/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-persistence/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/persistence/DiaryEntityRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.persistence;
2 |
3 | import com.feiniaojin.ddd.aigc.domain.DiaryEntity;
4 | import com.feiniaojin.ddd.aigc.domain.DiaryEntityId;
5 | import com.feiniaojin.ddd.aigc.domain.DiaryEntityRepository;
6 | import com.feiniaojin.ddd.aigc.infrastructure.persistence.data.Diary;
7 | import com.feiniaojin.ddd.aigc.infrastructure.persistence.jdbc.DiaryJdbcRepository;
8 | import jakarta.annotation.Resource;
9 | import org.springframework.stereotype.Component;
10 |
11 |
12 | @Component
13 | public class DiaryEntityRepositoryImpl implements DiaryEntityRepository {
14 |
15 | @Resource
16 | private DiaryJdbcRepository diaryJdbcRepository;
17 |
18 | @Override
19 | public DiaryEntity load(DiaryEntityId entityId) {
20 |
21 | Diary diary = diaryJdbcRepository.findByDiaryId(entityId.getValue());
22 |
23 | DiaryEntity entity = new DiaryEntity();
24 |
25 | entity.setDiaryEntityId(entityId);
26 | entity.setContent(diary.getContent());
27 | entity.setUid(diary.getUid());
28 | entity.setDiaryDateStr(diary.getDiaryDateStr());
29 | entity.setDiaryDate(diary.getDiaryDate());
30 |
31 | entity.setId(diary.getId());
32 | entity.setCreatedBy(diary.getCreatedBy());
33 | entity.setCreatedDate(diary.getCreatedDate());
34 | entity.setLastModifiedBy(diary.getModifiedBy());
35 | entity.setLastModifiedDate(diary.getLastModifiedDate());
36 | entity.setVersion(diary.getVersion());
37 | return entity;
38 | }
39 |
40 | @Override
41 | public void save(DiaryEntity entity) {
42 |
43 | Diary diary = new Diary();
44 |
45 | diary.setContent(entity.getContent());
46 | diary.setDiaryDate(entity.getDiaryDate());
47 | diary.setDiaryDateStr(entity.getDiaryDateStr());
48 | diary.setUid(entity.getUid());
49 | diary.setDiaryId(entity.getDiaryEntityId().getValue());
50 |
51 | diary.setVersion(entity.getVersion());
52 | diary.setId(entity.getId());
53 | diary.setDeleted(entity.getDeleted());
54 | diary.setCreatedDate(entity.getCreatedDate());
55 | diary.setLastModifiedDate(entity.getCreatedDate());
56 |
57 | diaryJdbcRepository.save(diary);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-persistence/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/persistence/JdbcConfig.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.persistence;
2 |
3 | import org.apache.ibatis.session.SqlSessionFactory;
4 | import org.mybatis.spring.SqlSessionFactoryBean;
5 | import org.mybatis.spring.annotation.MapperScan;
6 | import org.mybatis.spring.annotation.MapperScans;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.context.annotation.Import;
10 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
11 | import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;
12 | import org.springframework.data.jdbc.repository.config.MyBatisJdbcConfiguration;
13 |
14 | import javax.sql.DataSource;
15 |
16 | @Configuration
17 | @EnableJdbcRepositories
18 | @Import(MyBatisJdbcConfiguration.class)
19 | @MapperScans(@MapperScan("com.feiniaojin.ddd.aigc.infrastructure.persistence.mapper"))
20 | public class JdbcConfig {
21 | @Bean
22 | public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
23 | SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
24 | sessionFactoryBean.setDataSource(dataSource);
25 |
26 | // 添加映射器路径
27 | PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
28 | sessionFactoryBean.setMapperLocations(resolver.getResources("classpath:mappers/*.xml"));
29 |
30 | return sessionFactoryBean.getObject();
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-persistence/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/persistence/StickyNoteEntityRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.persistence;
2 |
3 | import com.feiniaojin.ddd.aigc.domain.DiaryEntityId;
4 | import com.feiniaojin.ddd.aigc.domain.StickyNoteEntity;
5 | import com.feiniaojin.ddd.aigc.domain.StickyNoteEntityId;
6 | import com.feiniaojin.ddd.aigc.domain.StickyNoteEntityRepository;
7 | import com.feiniaojin.ddd.aigc.infrastructure.persistence.data.StickyNote;
8 | import com.feiniaojin.ddd.aigc.infrastructure.persistence.jdbc.StickyNoteJdbcRepository;
9 | import com.google.gson.Gson;
10 | import com.google.gson.reflect.TypeToken;
11 | import jakarta.annotation.Resource;
12 | import org.springframework.stereotype.Component;
13 |
14 | import java.util.ArrayList;
15 | import java.util.List;
16 |
17 | @Component
18 | public class StickyNoteEntityRepositoryImpl implements StickyNoteEntityRepository {
19 |
20 | Gson gson = new Gson();
21 |
22 | @Resource
23 | private StickyNoteJdbcRepository jdbcRepository;
24 |
25 | @Override
26 | public StickyNoteEntity load(StickyNoteEntityId entityId) {
27 |
28 | String entityIdValue = entityId.getValue();
29 |
30 | StickyNote stickyNote = jdbcRepository.queryOneByBizId(entityIdValue);
31 |
32 | StickyNoteEntity entity = new StickyNoteEntity();
33 | entity.setStickyNoteEntityId(entityId);
34 | entity.setContent(stickyNote.getContent());
35 | entity.setUid(stickyNote.getUid());
36 | entity.setDiaryEntityId(new DiaryEntityId(stickyNote.getDiaryId()));
37 | String participants = stickyNote.getParticipants();
38 | List pList = gson.fromJson(participants, new TypeToken>() {
39 | }.getType());
40 | entity.setParticipants(pList);
41 | entity.setOccurrenceTime(stickyNote.getOccurrenceTime());
42 |
43 | //维护层超类型
44 | entity.setId(stickyNote.getId());
45 | entity.setDeleted(stickyNote.getDeleted());
46 | entity.setVersion(stickyNote.getVersion());
47 | entity.setCreatedDate(stickyNote.getCreatedDate());
48 | entity.setLastModifiedDate(stickyNote.getLastModifiedDate());
49 |
50 | return entity;
51 | }
52 |
53 | @Override
54 | public void save(StickyNoteEntity entity) {
55 |
56 | StickyNote stickyNote = new StickyNote();
57 |
58 | stickyNote.setStickyNoteId(entity.getStickyNoteEntityId().getValue());
59 | stickyNote.setDiaryId(entity.getDiaryEntityId().getValue());
60 | stickyNote.setUid(entity.getUid());
61 | stickyNote.setContent(entity.getContent());
62 | stickyNote.setParticipants(gson.toJson(entity.getParticipants()));
63 | stickyNote.setOccurrenceTime(entity.getOccurrenceTime());
64 |
65 | stickyNote.setId(entity.getId());
66 | stickyNote.setVersion(entity.getVersion());
67 | stickyNote.setDeleted(entity.getDeleted());
68 | stickyNote.setCreatedDate(entity.getCreatedDate());
69 | stickyNote.setLastModifiedDate(entity.getLastModifiedDate());
70 |
71 | jdbcRepository.save(stickyNote);
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-persistence/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/persistence/data/Diary.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.persistence.data;
2 |
3 | import jakarta.annotation.Generated;
4 | import lombok.Data;
5 | import org.springframework.data.annotation.CreatedDate;
6 | import org.springframework.data.annotation.Id;
7 | import org.springframework.data.annotation.LastModifiedDate;
8 | import org.springframework.data.annotation.Version;
9 | import org.springframework.data.relational.core.mapping.Table;
10 |
11 | import java.io.Serializable;
12 | import java.util.Date;
13 |
14 | /**
15 | * 表名称:t_diary
16 | * 表注释:日记表
17 | * NOTICE:本文件由代码生成器code-generator生成,不要在本文件手工追加任何内容,因为随时可能重新生成替换
18 | * github:https://github.com/feiniaojin/code-generator
19 | */
20 | @Data
21 | @Table("t_diary")
22 | @Generated("generator")
23 | public class Diary implements Serializable {
24 | /**
25 | * 自增主键
26 | */
27 | @Id
28 | private Long id;
29 | /**
30 | * 日记id
31 | */
32 | private String diaryId;
33 | /**
34 | * 日记正文
35 | */
36 | private String content;
37 | /**
38 | * 日记对应的时间
39 | */
40 | private Date diaryDate;
41 | /**
42 | * 日记对应的时间,字符串,yyyyMMDD
43 | */
44 | private String diaryDateStr;
45 | /**
46 | * 用户ID
47 | */
48 | private String uid;
49 | /**
50 | * 逻辑删除标记[0-正常;1-已删除]
51 | */
52 | private Integer deleted;
53 | /**
54 | * 创建人
55 | */
56 | private String createdBy;
57 | /**
58 | * 创建时间
59 | */
60 | @CreatedDate
61 | private Date createdDate;
62 | /**
63 | * 更新人
64 | */
65 | private String modifiedBy;
66 | /**
67 | * 更新时间
68 | */
69 | @LastModifiedDate
70 | private Date lastModifiedDate;
71 | /**
72 | * 乐观锁
73 | */
74 | @Version
75 | private Long version;
76 | }
77 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-persistence/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/persistence/data/StickyNote.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.persistence.data;
2 |
3 | import jakarta.annotation.Generated;
4 | import lombok.Data;
5 | import org.springframework.data.annotation.CreatedDate;
6 | import org.springframework.data.annotation.Id;
7 | import org.springframework.data.annotation.LastModifiedDate;
8 | import org.springframework.data.annotation.Version;
9 | import org.springframework.data.relational.core.mapping.Table;
10 |
11 | import java.io.Serializable;
12 | import java.util.Date;
13 |
14 | /**
15 | * 表名称:t_sticky_note
16 | * 表注释:日记贴纸表
17 | * NOTICE:本文件由代码生成器code-generator生成,不要在本文件手工追加任何内容,因为随时可能重新生成替换
18 | * github:https://github.com/feiniaojin/code-generator
19 | */
20 | @Data
21 | @Table("t_sticky_note")
22 | @Generated("generator")
23 | public class StickyNote implements Serializable {
24 | /**
25 | * 自增主键
26 | */
27 | @Id
28 | private Long id;
29 | /**
30 | * 贴纸id
31 | */
32 | private String stickyNoteId;
33 | /**
34 | * 贴纸正文
35 | */
36 | private String content;
37 | /**
38 | * 日记ID
39 | */
40 | private String diaryId;
41 | /**
42 | * 用户ID
43 | */
44 | private String uid;
45 | /**
46 | * 参与者,字符串数组的json,['aaa','bbb']
47 | */
48 | private String participants;
49 | /**
50 | * 创建时间
51 | */
52 | private Date occurrenceTime;
53 | /**
54 | * 逻辑删除标记[0-正常;1-已删除]
55 | */
56 | private Integer deleted;
57 | /**
58 | * 创建人
59 | */
60 | private String createdBy;
61 | /**
62 | * 创建时间
63 | */
64 | @CreatedDate
65 | private Date createdDate;
66 | /**
67 | * 更新人
68 | */
69 | private String modifiedBy;
70 | /**
71 | * 更新时间
72 | */
73 | @LastModifiedDate
74 | private Date lastModifiedDate;
75 | /**
76 | * 乐观锁
77 | */
78 | @Version
79 | private Long version;
80 | }
81 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-persistence/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/persistence/jdbc/DiaryJdbcRepository.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.persistence.jdbc;
2 |
3 | import com.feiniaojin.ddd.aigc.infrastructure.persistence.data.Diary;
4 | import org.springframework.data.jdbc.repository.query.Query;
5 | import org.springframework.data.repository.CrudRepository;
6 | import org.springframework.data.repository.query.Param;
7 | import org.springframework.stereotype.Repository;
8 |
9 | /**
10 | * 表名称:t_diary自动生成的Repository
11 | * 表注释:日记表
12 | * NOTICE:本文件由代码生成器code-generator生成,不要在本文件手工追加任何内容,因为随时可能重新生成替换
13 | * github:https://github.com/feiniaojin/code-generator
14 | */
15 | @Repository
16 | public interface DiaryJdbcRepository extends CrudRepository {
17 |
18 | @Query("select * from t_diary where diary_id=:diaryId limit 1")
19 | Diary findByDiaryId(@Param("diaryId") String diaryId);
20 | }
21 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-persistence/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/persistence/jdbc/StickyNoteJdbcRepository.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.persistence.jdbc;
2 |
3 | import com.feiniaojin.ddd.aigc.infrastructure.persistence.data.StickyNote;
4 | import org.springframework.data.jdbc.repository.query.Query;
5 | import org.springframework.data.repository.CrudRepository;
6 | import org.springframework.stereotype.Repository;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * 表名称:t_sticky_note自动生成的Repository
12 | * 表注释:日记贴纸表
13 | * NOTICE:本文件由代码生成器code-generator生成,不要在本文件手工追加任何内容,因为随时可能重新生成替换
14 | * github:https://github.com/feiniaojin/code-generator
15 | */
16 | @Repository
17 | public interface StickyNoteJdbcRepository extends CrudRepository {
18 | @Query("select * from t_sticky_note where sticky_note_id=:stickyNoteId and deleted=0 limit 1")
19 | StickyNote queryOneByBizId(String stickyNoteId);
20 |
21 | @Query("select sticky_note_id from t_sticky_note where diary_id=:diaryId and deleted=0")
22 | List queryStickyNoteIdByDiaryId(String diaryId);
23 |
24 | @Query("select * from t_sticky_note where diary_id=:diaryId and deleted=0")
25 | List queryListByDiaryId(String diaryId);
26 | }
27 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-persistence/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/persistence/mapper/DiaryMapper.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.persistence.mapper;
2 |
3 | import com.feiniaojin.ddd.aigc.infrastructure.persistence.data.Diary;
4 | import jakarta.annotation.Generated;
5 | import org.apache.ibatis.annotations.Param;
6 | import org.springframework.stereotype.Repository;
7 |
8 | import java.util.List;
9 | import java.util.Map;
10 |
11 | /**
12 | * 表名称:t_diary自动生成的Mapper
13 | * 表注释:日记表
14 | * NOTICE:本文件由代码生成器code-generator生成
15 | * github:https://github.com/feiniaojin/code-generator
16 | */
17 | @Generated("generator")
18 | @Repository
19 | public interface DiaryMapper {
20 | int insert(Diary record);
21 | Diary findOneById(@Param("id")Long id);
22 |
23 | int countForPageList(Map paramMap);
24 |
25 | List pageList(Map paramMap);
26 | }
27 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-persistence/src/main/java/com/feiniaojin/ddd/aigc/infrastructure/persistence/mapper/StickyNoteMapper.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.infrastructure.persistence.mapper;
2 |
3 | import com.feiniaojin.ddd.aigc.infrastructure.persistence.data.StickyNote;
4 | import jakarta.annotation.Generated;
5 | import org.apache.ibatis.annotations.Param;
6 | import org.springframework.stereotype.Repository;
7 |
8 |
9 | /**
10 | * 表名称:t_sticky_note自动生成的Mapper
11 | * 表注释:日记贴纸表
12 | * NOTICE:本文件由代码生成器code-generator生成
13 | * github:https://github.com/feiniaojin/code-generator
14 | */
15 | @Generated("generator")
16 | @Repository
17 | public interface StickyNoteMapper {
18 | int insert(StickyNote record);
19 | StickyNote findOneById(@Param("id")Long id);
20 | }
21 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-persistence/src/main/resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-infrastructure-persistence/src/main/resources/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-persistence/src/main/resources/ddd-aigc.sql:
--------------------------------------------------------------------------------
1 | CREATE DATABASE db_ddd_aigc;
2 |
3 | USE db_ddd_aigc;
4 |
5 | CREATE TABLE `t_diary` (
6 | `id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增主键',
7 | `diary_id` varchar(64) NULL COMMENT '日记id',
8 | `content` varchar(15000) NULL COMMENT '日记正文',
9 | `diary_date` DATETIME DEFAULT NULL COMMENT '日记对应的时间',
10 | `diary_date_str` varchar(32) DEFAULT NULL COMMENT '日记对应的时间,字符串,yyyyMMDD',
11 | `uid` varchar(64) NULL COMMENT '用户ID',
12 | `deleted` tinyint NULL DEFAULT 0 COMMENT '逻辑删除标记[0-正常;1-已删除]',
13 | `created_by` VARCHAR(100) COMMENT '创建人',
14 | `created_date` DATETIME NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
15 | `modified_by` VARCHAR(100) COMMENT '更新人',
16 | `modified_date` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
17 | `version` bigint DEFAULT 1 COMMENT '乐观锁',
18 | PRIMARY KEY (`id`),
19 | INDEX `idx_diaryId`(`diary_id`),
20 | UNIQUE INDEX `u_idx_uid_diaryDateStr` (`uid`,diary_date_str)
21 | ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE utf8mb4_bin COMMENT '日记表';
22 |
23 |
24 | CREATE TABLE `t_sticky_note` (
25 | `id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增主键',
26 | `sticky_note_id` varchar(64) NOT NULL COMMENT '贴纸id',
27 | `content` varchar(2000) NULL COMMENT '贴纸正文',
28 | `diary_id` varchar(64) NULL COMMENT '日记ID',
29 | `uid` varchar(64) NULL COMMENT '用户ID',
30 | `participants` varchar(255) NULL COMMENT '参与者,字符串数组的json,[\'aaa\',\'bbb\']',
31 | `occurrence_time` DATETIME NULL COMMENT '创建时间',
32 | `deleted` tinyint NULL DEFAULT 0 COMMENT '逻辑删除标记[0-正常;1-已删除]',
33 | `created_by` VARCHAR(100) COMMENT '创建人',
34 | `created_date` DATETIME NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
35 | `modified_by` VARCHAR(100) COMMENT '更新人',
36 | `modified_date` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
37 | `version` bigint DEFAULT 1 COMMENT '乐观锁',
38 | PRIMARY KEY (`id`),
39 | INDEX `idx_stickyNoteId`(`sticky_note_id`)
40 | ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE utf8mb4_bin COMMENT '日记贴纸表';
41 |
42 |
43 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-persistence/src/main/resources/mappers/DiaryMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | id,
24 | diary_id,
25 | content,
26 | diary_date,
27 | diary_date_str,
28 | uid,
29 | deleted,
30 | created_by,
31 | created_time,
32 | modified_by,
33 | modified_time,
34 | version
35 |
36 |
37 | insert into t_diary (
38 | id,
39 | diary_id,
40 | content,
41 | diary_date,
42 | diary_date_str,
43 | uid,
44 | deleted,
45 | created_by,
46 | created_time,
47 | modified_by,
48 | modified_time,
49 | version
50 | )
51 |
52 | #{id},
53 | #{diaryId},
54 | #{content},
55 | #{diaryDate},
56 | #{diaryDateStr},
57 | #{uid},
58 | #{deleted},
59 | #{createdBy},
60 | #{createdTime},
61 | #{modifiedBy},
62 | #{modifiedTime},
63 | #{version}
64 |
65 |
66 |
67 | select
68 |
69 | from t_diary where id=#{id}
70 |
71 |
72 |
73 | select
74 | count(1)
75 | from t_diary
76 |
77 |
78 | and uid=#{uid}
79 |
80 |
81 |
82 |
83 |
84 | select
85 |
86 | from t_diary
87 |
88 |
89 | and uid=#{uid}
90 |
91 |
92 | order by diary_date_str desc
93 | limit #{limitStart},#{limitEnd}
94 |
95 |
96 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-persistence/src/main/resources/mappers/StickyNoteMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | id,
25 | sticky_note_id,
26 | content,
27 | diary_id,
28 | uid,
29 | participants,
30 | occurrence_time,
31 | deleted,
32 | created_by,
33 | created_time,
34 | modified_by,
35 | modified_time,
36 | version
37 |
38 |
39 | insert into t_sticky_note (
40 | id,
41 | sticky_note_id,
42 | content,
43 | diary_id,
44 | uid,
45 | participants,
46 | occurrence_time,
47 | deleted,
48 | created_by,
49 | created_time,
50 | modified_by,
51 | modified_time,
52 | version
53 | )
54 |
55 | #{id},
56 | #{stickyNoteId},
57 | #{content},
58 | #{diaryId},
59 | #{uid},
60 | #{participants},
61 | #{occurrenceTime},
62 | #{deleted},
63 | #{createdBy},
64 | #{createdTime},
65 | #{modifiedBy},
66 | #{modifiedTime},
67 | #{version}
68 |
69 |
70 |
71 | select
72 |
73 | from t_sticky_note where id=#{id}
74 |
75 |
76 |
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-persistence/src/test/java/com/feiniaojin/ddd/aigc/infrastructure/persistence/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-infrastructure-persistence/src/test/java/com/feiniaojin/ddd/aigc/infrastructure/persistence/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-persistence/src/test/resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-infrastructure-persistence/src/test/resources/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-infrastructure-publisher/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ddd-aigc
5 | com.feiniaojin.ddd.aigc
6 | 1.0-SNAPSHOT
7 |
8 | 4.0.0
9 |
10 | ddd-aigc-infrastructure-publisher
11 |
12 |
13 | 8
14 | 8
15 |
16 |
17 |
18 |
19 | com.feiniaojin.ddd.aigc
20 | ddd-aigc-domain
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/ddd-aigc-launcher/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ddd-aigc
5 | com.feiniaojin.ddd.aigc
6 | 1.0-SNAPSHOT
7 |
8 | 4.0.0
9 |
10 | ddd-aigc-launcher
11 |
12 |
13 | 8
14 | 8
15 |
16 |
17 |
18 |
19 |
20 | org.projectlombok
21 | lombok
22 | true
23 |
24 |
25 | com.feiniaojin.ddd.aigc
26 | ddd-aigc-user-interface-web
27 |
28 |
29 | com.feiniaojin.ddd.aigc
30 | ddd-aigc-user-interface-provider
31 |
32 |
33 | com.feiniaojin.ddd.aigc
34 | ddd-aigc-user-interface-subscriber
35 |
36 |
37 | com.feiniaojin.ddd.aigc
38 | ddd-aigc-user-interface-worker
39 |
40 |
41 |
42 |
43 |
44 |
45 | org.springframework.boot
46 | spring-boot-maven-plugin
47 |
48 |
49 |
50 | org.projectlombok
51 | lombok
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/ddd-aigc-launcher/src/main/java/com/feiniaojin/ddd/aigc/Launcher.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class Launcher {
8 | public static void main(String[] args) {
9 | SpringApplication.run(Launcher.class, args);
10 | }
11 | }
--------------------------------------------------------------------------------
/ddd-aigc-launcher/src/main/resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-launcher/src/main/resources/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-launcher/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 9899
3 | servlet:
4 | encoding:
5 | charset: UTF-8
6 | spring:
7 | mvc:
8 | async:
9 | request-timeout: 300000
10 | jackson:
11 | time-zone: GMT+8
12 | date-format: yyyy-MM-dd HH:mm:ss
13 | datasource:
14 | url: jdbc:mysql://localhost:3306/db_ddd_aigc
15 | username: root
16 | password: abc123456
17 | driver-class-name: com.mysql.cj.jdbc.Driver
18 | type: com.zaxxer.hikari.HikariDataSource
19 | hikari:
20 | minimum-idle: 4
21 | maximum-pool-size: 15
22 | auto-commit: true
23 | idle-timeout: 30000
24 | pool-name: DatebookHikariCP
25 | max-lifetime: 1800000
26 | connection-timeout: 10000
27 | ai:
28 | openai:
29 | moderation:
30 | api-key: key
31 | chat:
32 | enabled: false
33 | embedding:
34 | enabled: false
35 | image:
36 | enabled: false
37 | audio:
38 | transcription:
39 | enabled: false
40 | speech:
41 | enabled: false
42 | ollama:
43 | chat:
44 | enabled: false
45 | # 定义所有服务商的配置模板
46 | providers:
47 | deepseek-official:
48 | base-url: https://api.deepseek.com/v1
49 | api-key: replace_with_your_api_key
50 | model: deepseek-reasoner
51 | siliconflow:
52 | base-url: https://api.siliconflow.cn/v1
53 | api-key: replace_with_your_api_key
54 | model: deepseek-ai/DeepSeek-R1
55 | openai:
56 | base-url: https://api.openai.com/v1
57 | api-key: replace_with_your_api_key
58 | model: gpt-4o-mini
59 | ollama:
60 | base-url: http://localhost:11434
61 | model: deepseek-r1:1.5b
62 | web:
63 | resources:
64 | static-locations: classpath:/static/,classpath:/views/
65 | graceful-response:
66 | print-exception-in-global-advice: true
67 |
68 | ddd-aigc:
69 | provider-name: ollama
70 | default-system-message: 根据提示,生成一篇日记,要求不得涉及政治、色情等内容。
71 |
72 |
73 |
--------------------------------------------------------------------------------
/ddd-aigc-launcher/src/test/java/com/feiniaojin/ddd/aigc/launcher/test/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-launcher/src/test/java/com/feiniaojin/ddd/aigc/launcher/test/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-launcher/src/test/resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-launcher/src/test/resources/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-user-interface-provider/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | com.feiniaojin.ddd.aigc
6 | ddd-aigc
7 | 1.0-SNAPSHOT
8 |
9 |
10 | ddd-aigc-user-interface-provider
11 |
12 |
13 | 8
14 | 8
15 | UTF-8
16 |
17 |
18 |
19 | com.feiniaojin.ddd.aigc
20 | ddd-aigc-application-service
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/ddd-aigc-user-interface-provider/src/main/java/com/feiniaojin/Main.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin;
2 |
3 | // Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
4 | // then press Enter. You can now see whitespace characters in your code.
5 | public class Main {
6 | public static void main(String[] args) {
7 | // Press Opt+Enter with your caret at the highlighted text to see how
8 | // IntelliJ IDEA suggests fixing it.
9 | System.out.printf("Hello and welcome!");
10 |
11 | // Press Ctrl+R or click the green arrow button in the gutter to run the code.
12 | for (int i = 1; i <= 5; i++) {
13 |
14 | // Press Ctrl+D to start debugging your code. We have set one breakpoint
15 | // for you, but you can always add more by pressing Cmd+F8.
16 | System.out.println("i = " + i);
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/ddd-aigc-user-interface-subscriber/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | com.feiniaojin.ddd.aigc
6 | ddd-aigc
7 | 1.0-SNAPSHOT
8 |
9 |
10 | ddd-aigc-user-interface-subscriber
11 |
12 |
13 | 8
14 | 8
15 | UTF-8
16 |
17 |
18 |
19 |
20 | com.feiniaojin.ddd.aigc
21 | ddd-aigc-application-service
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ddd-aigc-user-interface-subscriber/src/main/java/com/feiniaojin/Main.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin;
2 |
3 | // Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
4 | // then press Enter. You can now see whitespace characters in your code.
5 | public class Main {
6 | public static void main(String[] args) {
7 | // Press Opt+Enter with your caret at the highlighted text to see how
8 | // IntelliJ IDEA suggests fixing it.
9 | System.out.printf("Hello and welcome!");
10 |
11 | // Press Ctrl+R or click the green arrow button in the gutter to run the code.
12 | for (int i = 1; i <= 5; i++) {
13 |
14 | // Press Ctrl+D to start debugging your code. We have set one breakpoint
15 | // for you, but you can always add more by pressing Cmd+F8.
16 | System.out.println("i = " + i);
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/ddd-aigc-user-interface-web/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ddd-aigc
5 | com.feiniaojin.ddd.aigc
6 | 1.0-SNAPSHOT
7 |
8 | 4.0.0
9 |
10 | ddd-aigc-user-interface-web
11 |
12 |
13 | 8
14 | 8
15 |
16 |
17 |
18 |
19 | com.feiniaojin
20 | graceful-response
21 | 3.1.0
22 |
23 |
24 | org.springframework.boot
25 | spring-boot-starter-web
26 | 2.7.15
27 |
28 |
29 | com.feiniaojin.ddd.aigc
30 | ddd-aigc-application-service
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/ddd-aigc-user-interface-web/src/main/java/com/feiniaojin/ddd/aigc/ui/web/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-user-interface-web/src/main/java/com/feiniaojin/ddd/aigc/ui/web/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-user-interface-web/src/main/java/com/feiniaojin/ddd/aigc/ui/web/WebConfig.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.ui.web;
2 |
3 | import com.feiniaojin.gracefulresponse.EnableGracefulResponse;
4 | import org.springframework.context.annotation.Configuration;
5 |
6 | @Configuration
7 | @EnableGracefulResponse
8 | public class WebConfig {
9 |
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/ddd-aigc-user-interface-web/src/main/java/com/feiniaojin/ddd/aigc/ui/web/controller/DiaryController.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.ui.web.controller;
2 |
3 | import com.feiniaojin.ddd.aigc.application.service.diary.DiaryCommandApplicationService;
4 | import com.feiniaojin.ddd.aigc.application.service.diary.DiaryQueryApplicationService;
5 | import com.feiniaojin.ddd.aigc.application.service.diary.dto.*;
6 | import com.feiniaojin.gracefulresponse.data.PageBean;
7 | import jakarta.annotation.Resource;
8 | import org.springframework.web.bind.annotation.RequestBody;
9 | import org.springframework.web.bind.annotation.RequestMapping;
10 | import org.springframework.web.bind.annotation.RestController;
11 |
12 |
13 | @RestController
14 | @RequestMapping("/diary")
15 | public class DiaryController {
16 |
17 | @Resource
18 | private DiaryCommandApplicationService commandApplicationService;
19 |
20 | @Resource
21 | private DiaryQueryApplicationService queryApplicationService;
22 |
23 | @RequestMapping("/create")
24 | public DiaryCreateView createDiary(@RequestBody DiaryCreateCommand command) {
25 | return commandApplicationService.createDiary(command);
26 | }
27 |
28 | @RequestMapping("/pageList")
29 | public PageBean pageList(DiaryQuery query) {
30 | return queryApplicationService.pageList(query);
31 | }
32 |
33 |
34 | @RequestMapping("/saveContent")
35 | public void saveContent(@RequestBody DiarySaveContentCommand command) {
36 | commandApplicationService.saveContent(command);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/ddd-aigc-user-interface-web/src/main/java/com/feiniaojin/ddd/aigc/ui/web/controller/StickyNoteController.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin.ddd.aigc.ui.web.controller;
2 |
3 | import com.feiniaojin.ddd.aigc.application.service.stickynote.StickyNoteCommandApplicationService;
4 | import com.feiniaojin.ddd.aigc.application.service.stickynote.StickyNoteQueryApplicationService;
5 | import com.feiniaojin.ddd.aigc.application.service.stickynote.dto.*;
6 | import com.feiniaojin.gracefulresponse.api.ExcludeFromGracefulResponse;
7 | import jakarta.annotation.Resource;
8 | import org.springframework.http.HttpHeaders;
9 | import org.springframework.http.MediaType;
10 | import org.springframework.http.server.ServerHttpResponse;
11 | import org.springframework.web.bind.annotation.RequestBody;
12 | import org.springframework.web.bind.annotation.RequestMapping;
13 | import org.springframework.web.bind.annotation.RestController;
14 | import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
15 | import reactor.core.publisher.Flux;
16 |
17 | import java.io.IOException;
18 | import java.nio.charset.StandardCharsets;
19 | import java.util.concurrent.Executor;
20 | import java.util.concurrent.Executors;
21 |
22 |
23 | @RestController
24 | @RequestMapping("/stickyNote")
25 | public class StickyNoteController {
26 |
27 | @Resource
28 | private StickyNoteCommandApplicationService commandApplicationService;
29 |
30 | @Resource
31 | private StickyNoteQueryApplicationService queryApplicationService;
32 |
33 | private final Executor asyncExecutor = Executors.newFixedThreadPool(4);
34 |
35 |
36 | @RequestMapping("/generateDiaryContent")
37 | public StickyNoteGenerateContentView generateDiaryContent(StickyNoteGenerateContentQuery query) {
38 | return queryApplicationService.generateDiaryContent(query);
39 | }
40 |
41 | @RequestMapping("/create")
42 | public StickyNoteCreateView create(@RequestBody StickyNoteCreateCommand command) {
43 | return commandApplicationService.createStickyNote(command);
44 | }
45 |
46 | @RequestMapping("/modify")
47 | public void modify(@RequestBody StickyNoteModifyCommand command) {
48 | commandApplicationService.modifyStickyNote(command);
49 | }
50 |
51 | /**
52 | * 这个接口阻塞和非阻塞混用,仅用于演示
53 | * 建议使用webflux+r2dbc
54 | *
55 | * @param query
56 | * @return
57 | */
58 | @RequestMapping(value = "/generateDiaryContentSse",
59 | produces = "text/event-stream")
60 | public SseEmitter generateDiaryContentSse(StickyNoteGenerateContentQuery query) {
61 | SseEmitter emitter = new SseEmitterUTF8(300_000L);
62 | Flux stringFlux = queryApplicationService.generateDiaryContentStream(query);
63 | asyncExecutor.execute(() -> {
64 | stringFlux.subscribe(data -> {
65 | try {
66 | emitter.send(data);
67 | } catch (IOException e) {
68 | emitter.completeWithError(e);
69 | }
70 | },
71 | emitter::completeWithError,
72 | emitter::complete);
73 | });
74 | return emitter;
75 | }
76 |
77 | public static class SseEmitterUTF8 extends SseEmitter {
78 | public SseEmitterUTF8(Long timeout) {
79 | super(timeout);
80 | }
81 |
82 | @Override
83 | protected void extendResponse(ServerHttpResponse response) {
84 | super.extendResponse(response);
85 | HttpHeaders headers = response.getHeaders();
86 | // 强制设置媒体类型与编码
87 | headers.setContentType(
88 | new MediaType("text", "event-stream", StandardCharsets.UTF_8)
89 | );
90 | }
91 | }
92 |
93 |
94 | /**
95 | * 这个接口阻塞和非阻塞混用,仅用于演示
96 | * 建议使用webflux+r2dbc
97 | *
98 | * @param query
99 | * @return
100 | */
101 | @RequestMapping(value = "/generateDiaryContentFlux", produces = "text/html;charset=utf-8")
102 | // @RequestMapping(value = "/generateDiaryContentFlux", produces = "text/event-stream;charset=utf-8")
103 | @ExcludeFromGracefulResponse
104 | public Flux generateDiaryContentFlux(StickyNoteGenerateContentQuery query) {
105 | return queryApplicationService.generateDiaryContentStream(query);
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/ddd-aigc-user-interface-web/src/main/resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-user-interface-web/src/main/resources/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-user-interface-web/src/test/java/com/feiniaojin/ddd/aigc/ui/web/test/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-user-interface-web/src/test/java/com/feiniaojin/ddd/aigc/ui/web/test/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-user-interface-web/src/test/resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiniaojin/ddd-aigc/92f60ab4568fb3b31cfff45d4a8a0bf8f8cc1d24/ddd-aigc-user-interface-web/src/test/resources/.gitkeep
--------------------------------------------------------------------------------
/ddd-aigc-user-interface-worker/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | com.feiniaojin.ddd.aigc
6 | ddd-aigc
7 | 1.0-SNAPSHOT
8 |
9 |
10 | ddd-aigc-user-interface-worker
11 |
12 |
13 | 8
14 | 8
15 | UTF-8
16 |
17 |
18 |
19 |
20 | com.feiniaojin.ddd.aigc
21 | ddd-aigc-application-service
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ddd-aigc-user-interface-worker/src/main/java/com/feiniaojin/Main.java:
--------------------------------------------------------------------------------
1 | package com.feiniaojin;
2 |
3 | // Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
4 | // then press Enter. You can now see whitespace characters in your code.
5 | public class Main {
6 | public static void main(String[] args) {
7 | // Press Opt+Enter with your caret at the highlighted text to see how
8 | // IntelliJ IDEA suggests fixing it.
9 | System.out.printf("Hello and welcome!");
10 |
11 | // Press Ctrl+R or click the green arrow button in the gutter to run the code.
12 | for (int i = 1; i <= 5; i++) {
13 |
14 | // Press Ctrl+D to start debugging your code. We have set one breakpoint
15 | // for you, but you can always add more by pressing Cmd+F8.
16 | System.out.println("i = " + i);
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.4.2
9 |
10 | com.feiniaojin.ddd.aigc
11 | ddd-aigc
12 | pom
13 | 1.0-SNAPSHOT
14 |
15 |
16 | 17
17 | 17
18 | 17
19 |
20 |
21 |
22 |
23 |
24 | org.springframework.ai
25 | spring-ai-bom
26 | 1.0.0-M6
27 | pom
28 | import
29 |
30 |
31 | com.google.code.gson
32 | gson
33 | 2.8.9
34 |
35 |
36 | com.feiniaojin
37 | graceful-response
38 | 5.0.5-boot3
39 |
40 |
41 | com.fasterxml.jackson.core
42 | jackson-core
43 | 2.15.2
44 |
45 |
46 | com.fasterxml.jackson.core
47 | jackson-databind
48 | 2.15.2
49 |
50 |
51 | com.fasterxml.jackson.core
52 | jackson-annotations
53 | 2.15.2
54 |
55 |
56 | org.apache.commons
57 | commons-lang3
58 | 3.4
59 |
60 |
61 | com.feiniaojin.ddd.aigc
62 | ddd-aigc-user-interface-worker
63 | 1.0-SNAPSHOT
64 |
65 |
66 | com.feiniaojin.ddd.aigc
67 | ddd-aigc-user-interface-subscriber
68 | 1.0-SNAPSHOT
69 |
70 |
71 | com.feiniaojin.ddd.aigc
72 | ddd-aigc-user-interface-provider
73 | 1.0-SNAPSHOT
74 |
75 |
76 | com.feiniaojin.ddd.aigc
77 | ddd-aigc-infrastructure-cache
78 | 1.0-SNAPSHOT
79 |
80 |
81 | com.feiniaojin.ddd.aigc
82 | ddd-aigc-domain
83 | 1.0-SNAPSHOT
84 |
85 |
86 | com.feiniaojin.ddd.aigc
87 | ddd-aigc-infrastructure-persistence
88 | 1.0-SNAPSHOT
89 |
90 |
91 | com.feiniaojin.ddd.aigc
92 | ddd-aigc-infrastructure-publisher
93 | 1.0-SNAPSHOT
94 |
95 |
96 | com.feiniaojin.ddd.aigc
97 | ddd-aigc-infrastructure-gateway
98 | 1.0-SNAPSHOT
99 |
100 |
101 | com.feiniaojin.ddd.aigc
102 | ddd-aigc-application-service
103 | 1.0-SNAPSHOT
104 |
105 |
106 | com.feiniaojin.ddd.aigc
107 | ddd-aigc-user-interface-web
108 | 1.0-SNAPSHOT
109 |
110 |
111 | com.feiniaojin.ddd.aigc
112 | ddd-aigc-launcher
113 | 1.0-SNAPSHOT
114 |
115 |
116 | org.springframework.boot
117 | spring-boot-starter-data-jdbc
118 |
119 |
120 | org.springframework.boot
121 | spring-boot-starter-web
122 |
123 |
124 | org.springframework.kafka
125 | spring-kafka
126 |
127 |
128 |
129 |
130 | org.springframework.boot
131 | spring-boot-starter-data-jdbc
132 |
133 |
134 | org.springframework.boot
135 | spring-boot-starter-web
136 |
137 |
138 |
139 | com.h2database
140 | h2
141 | runtime
142 |
143 |
144 | com.mysql
145 | mysql-connector-j
146 | runtime
147 |
148 |
149 | org.projectlombok
150 | lombok
151 | 1.18.30
152 | true
153 |
154 |
155 | org.springframework.boot
156 | spring-boot-starter-test
157 | test
158 |
159 |
160 | com.feiniaojin
161 | ddd
162 | 1.0-SNAPSHOT
163 |
164 |
165 | org.mybatis.spring.boot
166 | mybatis-spring-boot-starter
167 | 3.0.4
168 |
169 |
170 | com.theokanning.openai-gpt3-java
171 | api
172 | 0.16.1
173 |
174 |
175 | com.theokanning.openai-gpt3-java
176 | client
177 | 0.16.1
178 |
179 |
180 | com.theokanning.openai-gpt3-java
181 | service
182 | 0.16.1
183 |
184 |
185 |
186 |
187 |
188 | ddd-aigc-domain
189 | ddd-aigc-application-service
190 | ddd-aigc-infrastructure-persistence
191 | ddd-aigc-infrastructure-publisher
192 | ddd-aigc-infrastructure-gateway
193 | ddd-aigc-infrastructure-cache
194 | ddd-aigc-user-interface-web
195 | ddd-aigc-user-interface-worker
196 | ddd-aigc-user-interface-provider
197 | ddd-aigc-user-interface-subscriber
198 | ddd-aigc-launcher
199 |
200 |
201 |
202 |
203 | spring-milestones
204 | Spring Milestones
205 | https://repo.spring.io/milestone
206 |
207 | false
208 |
209 |
210 |
211 | spring-snapshots
212 | Spring Snapshots
213 | https://repo.spring.io/snapshot
214 |
215 | false
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 | org.apache.maven.plugins
224 | maven-compiler-plugin
225 | 3.14.0
226 |
227 |
228 | --add-opens
229 | jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED
230 |
231 |
232 |
233 |
234 |
235 |
236 |
--------------------------------------------------------------------------------