├── .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 | [![pinWT1A.png](https://z1.ax1x.com/2023/10/31/pinWT1A.png)](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 | [![pinW76I.png](https://z1.ax1x.com/2023/10/31/pinW76I.png)](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 | [![pinWL0f.png](https://z1.ax1x.com/2023/10/31/pinWL0f.png)](https://imgse.com/i/pinWL0f) 37 | 38 | # 贡献者 39 | 40 | 41 | 42 | 43 | # 点赞趋势 44 | 45 | [![Star History Chart](https://api.star-history.com/svg?repos=feiniaojin/ddd-aigc&type=Date)](https://star-history.com/#feiniaojin/ddd-aigc&Date) 46 | 47 | # DDD学习交流群 48 | 欢迎加入DDD交流群。微信扫以下二维码添加作者微信,标注“DDD”,好友申请通过后拉您进群。 49 |
pi1rmB6.jpg
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 | 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 | 20 | 21 | 45 | -------------------------------------------------------------------------------- /ddd-aigc-frontend/src/components/TheWelcome.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 95 | -------------------------------------------------------------------------------- /ddd-aigc-frontend/src/components/WelcomeItem.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 87 | -------------------------------------------------------------------------------- /ddd-aigc-frontend/src/components/icons/IconCommunity.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /ddd-aigc-frontend/src/components/icons/IconDocumentation.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /ddd-aigc-frontend/src/components/icons/IconEcosystem.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /ddd-aigc-frontend/src/components/icons/IconSupport.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /ddd-aigc-frontend/src/components/icons/IconTooling.vue: -------------------------------------------------------------------------------- 1 | 2 | 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 | 6 | 7 | 16 | -------------------------------------------------------------------------------- /ddd-aigc-frontend/src/views/BasicInfo.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 60 | 63 | -------------------------------------------------------------------------------- /ddd-aigc-frontend/src/views/Content.vue: -------------------------------------------------------------------------------- 1 | 55 | 56 | 91 | 92 | 95 | -------------------------------------------------------------------------------- /ddd-aigc-frontend/src/views/HomeView.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /ddd-aigc-frontend/src/views/WhiteBoard.vue: -------------------------------------------------------------------------------- 1 | 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 | 71 | 72 | 82 | 83 | 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 | 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 | --------------------------------------------------------------------------------