aiService.ts 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. import axios from 'axios'
  2. import type { Recipe, CuisineType } from '@/types'
  3. // AI服务配置 - 智谱AI
  4. const AI_CONFIG = {
  5. // baseURL: 'https://open.bigmodel.cn/api/paas/v4/',
  6. // apiKey: 'a835b9f6866d48ec956d341418df8a50.NuhlKYn58EkCb5iP',
  7. // model: 'glm-4-flash-250414',
  8. // temperature: 0.7,
  9. // timeout: 30000
  10. baseURL: 'https://api.deepseek.com/v1/',
  11. apiKey: 'sk-78d4fed678fa4a5ebc5f7beac54b1a78',
  12. model: 'deepseek-chat',
  13. temperature: 0.7,
  14. timeout: 30000
  15. }
  16. // 创建axios实例
  17. const aiClient = axios.create({
  18. baseURL: AI_CONFIG.baseURL,
  19. timeout: AI_CONFIG.timeout,
  20. headers: {
  21. 'Content-Type': 'application/json',
  22. Authorization: `Bearer ${AI_CONFIG.apiKey}`
  23. }
  24. })
  25. /**
  26. * 调用AI接口生成菜谱
  27. * @param ingredients 食材列表
  28. * @param cuisine 菜系信息
  29. * @param customPrompt 自定义提示词(可选)
  30. * @returns Promise<Recipe>
  31. */
  32. export const generateRecipe = async (ingredients: string[], cuisine: CuisineType, customPrompt?: string): Promise<Recipe> => {
  33. try {
  34. // 构建提示词
  35. let prompt = `${cuisine.prompt}
  36. 用户提供的食材:${ingredients.join('、')}`
  37. // 如果有自定义要求,添加到提示词中
  38. if (customPrompt) {
  39. prompt += `
  40. 用户的特殊要求:${customPrompt}`
  41. }
  42. prompt += `
  43. 请按照以下JSON格式返回菜谱:
  44. {
  45. "name": "菜品名称",
  46. "ingredients": ["食材1", "食材2"],
  47. "steps": [
  48. {
  49. "step": 1,
  50. "description": "步骤描述",
  51. "time": 5,
  52. "temperature": "中火"
  53. }
  54. ],
  55. "cookingTime": 30,
  56. "difficulty": "medium",
  57. "tips": ["技巧1", "技巧2"]
  58. }`
  59. // 调用智谱AI接口
  60. const response = await aiClient.post('/chat/completions', {
  61. model: AI_CONFIG.model,
  62. messages: [
  63. {
  64. role: 'system',
  65. content: '你是一位专业的厨师,请根据用户提供的食材和菜系要求,生成详细的菜谱。请严格按照JSON格式返回,不要包含任何其他文字。'
  66. },
  67. {
  68. role: 'user',
  69. content: prompt
  70. }
  71. ],
  72. temperature: AI_CONFIG.temperature,
  73. max_tokens: 2000,
  74. stream: false
  75. })
  76. // 解析AI响应
  77. const aiResponse = response.data.choices[0].message.content
  78. // 清理响应内容,提取JSON部分
  79. let cleanResponse = aiResponse.trim()
  80. if (cleanResponse.startsWith('```json')) {
  81. cleanResponse = cleanResponse.replace(/```json\s*/, '').replace(/```\s*$/, '')
  82. } else if (cleanResponse.startsWith('```')) {
  83. cleanResponse = cleanResponse.replace(/```\s*/, '').replace(/```\s*$/, '')
  84. }
  85. const recipeData = JSON.parse(cleanResponse)
  86. // 构建完整的Recipe对象
  87. const recipe: Recipe = {
  88. id: `recipe-${cuisine.id}-${Date.now()}`,
  89. name: recipeData.name || `${cuisine.name}推荐菜品`,
  90. cuisine: cuisine.name,
  91. ingredients: recipeData.ingredients || ingredients,
  92. steps: recipeData.steps || [
  93. { step: 1, description: '准备所有食材', time: 5 },
  94. { step: 2, description: '按照传统做法烹饪', time: 20 }
  95. ],
  96. cookingTime: recipeData.cookingTime || 25,
  97. difficulty: recipeData.difficulty || 'medium',
  98. tips: recipeData.tips || ['注意火候控制', '调味要适中']
  99. }
  100. return recipe
  101. } catch (error) {
  102. console.error(`生成${cuisine.name}菜谱失败:`, error)
  103. // 如果AI调用失败,返回一个基础的菜谱模板
  104. const fallbackRecipe: Recipe = {
  105. id: `recipe-${cuisine.id}-${Date.now()}`,
  106. name: `${cuisine.name}推荐:${ingredients.join('')}料理`,
  107. cuisine: cuisine.name,
  108. ingredients: ingredients,
  109. steps: [
  110. { step: 1, description: '准备所有食材,清洗干净', time: 5 },
  111. { step: 2, description: '热锅下油,爆香配料', time: 3 },
  112. { step: 3, description: '下主料翻炒至半熟', time: 8 },
  113. { step: 4, description: '调味炒制至熟透', time: 5 },
  114. { step: 5, description: '装盘即可享用', time: 1 }
  115. ],
  116. cookingTime: 22,
  117. difficulty: 'medium',
  118. tips: ['火候要掌握好,避免炒糊', '调料要适量,突出食材本味', '炒制过程中要勤翻动']
  119. }
  120. return fallbackRecipe
  121. }
  122. }
  123. /**
  124. * 批量生成多个菜系的菜谱
  125. * @param ingredients 食材列表
  126. * @param cuisines 菜系列表
  127. * @param customPrompt 自定义提示词(可选)
  128. * @returns Promise<Recipe[]>
  129. */
  130. export const generateMultipleRecipes = async (ingredients: string[], cuisines: CuisineType[], customPrompt?: string): Promise<Recipe[]> => {
  131. try {
  132. // 并发调用多个AI接口
  133. const promises = cuisines.map(cuisine => generateRecipe(ingredients, cuisine, customPrompt))
  134. const recipes = await Promise.all(promises)
  135. return recipes
  136. } catch (error) {
  137. console.error('批量生成菜谱失败:', error)
  138. throw new Error('批量生成菜谱失败')
  139. }
  140. }
  141. /**
  142. * 更新AI配置
  143. * @param config 新的配置
  144. */
  145. export const updateAIConfig = (config: Partial<typeof AI_CONFIG>) => {
  146. Object.assign(AI_CONFIG, config)
  147. // 更新axios实例配置
  148. aiClient.defaults.baseURL = AI_CONFIG.baseURL
  149. aiClient.defaults.headers['Authorization'] = `Bearer ${AI_CONFIG.apiKey}`
  150. }
  151. /**
  152. * 使用自定义提示词生成菜谱
  153. * @param ingredients 食材列表
  154. * @param customPrompt 自定义提示词
  155. * @returns Promise<Recipe>
  156. */
  157. export const generateCustomRecipe = async (ingredients: string[], customPrompt: string): Promise<Recipe> => {
  158. try {
  159. // 构建自定义提示词
  160. const prompt = `你是一位专业的厨师,请根据用户提供的食材和特殊要求,生成详细的菜谱。请严格按照JSON格式返回,不要包含任何其他文字。
  161. 用户提供的食材:${ingredients.join('、')}
  162. 用户的特殊要求:${customPrompt}
  163. 请按照以下JSON格式返回菜谱:
  164. {
  165. "name": "菜品名称",
  166. "ingredients": ["食材1", "食材2"],
  167. "steps": [
  168. {
  169. "step": 1,
  170. "description": "步骤描述",
  171. "time": 5,
  172. "temperature": "中火"
  173. }
  174. ],
  175. "cookingTime": 30,
  176. "difficulty": "medium",
  177. "tips": ["技巧1", "技巧2"]
  178. }`
  179. // 调用智谱AI接口
  180. const response = await aiClient.post('/chat/completions', {
  181. model: AI_CONFIG.model,
  182. messages: [
  183. {
  184. role: 'system',
  185. content: '你是一位专业的厨师,请根据用户提供的食材和特殊要求,生成详细的菜谱。请严格按照JSON格式返回,不要包含任何其他文字。'
  186. },
  187. {
  188. role: 'user',
  189. content: prompt
  190. }
  191. ],
  192. temperature: AI_CONFIG.temperature,
  193. max_tokens: 2000,
  194. stream: false
  195. })
  196. // 解析AI响应
  197. const aiResponse = response.data.choices[0].message.content
  198. // 清理响应内容,提取JSON部分
  199. let cleanResponse = aiResponse.trim()
  200. if (cleanResponse.startsWith('```json')) {
  201. cleanResponse = cleanResponse.replace(/```json\s*/, '').replace(/```\s*$/, '')
  202. } else if (cleanResponse.startsWith('```')) {
  203. cleanResponse = cleanResponse.replace(/```\s*/, '').replace(/```\s*$/, '')
  204. }
  205. const recipeData = JSON.parse(cleanResponse)
  206. // 构建完整的Recipe对象
  207. const recipe: Recipe = {
  208. id: `recipe-custom-${Date.now()}`,
  209. name: recipeData.name || '自定义菜品',
  210. cuisine: '自定义',
  211. ingredients: recipeData.ingredients || ingredients,
  212. steps: recipeData.steps || [
  213. { step: 1, description: '准备所有食材', time: 5 },
  214. { step: 2, description: '按照要求烹饪', time: 20 }
  215. ],
  216. cookingTime: recipeData.cookingTime || 25,
  217. difficulty: recipeData.difficulty || 'medium',
  218. tips: recipeData.tips || ['根据个人口味调整', '注意火候控制']
  219. }
  220. return recipe
  221. } catch (error) {
  222. console.error('生成自定义菜谱失败:', error)
  223. // 如果AI调用失败,返回一个基础的菜谱模板
  224. const fallbackRecipe: Recipe = {
  225. id: `recipe-custom-${Date.now()}`,
  226. name: `自定义:${ingredients.join('')}料理`,
  227. cuisine: '自定义',
  228. ingredients: ingredients,
  229. steps: [
  230. { step: 1, description: '准备所有食材,清洗干净', time: 5 },
  231. { step: 2, description: '根据要求进行烹饪处理', time: 10 },
  232. { step: 3, description: '调味并完成最后的制作', time: 8 },
  233. { step: 4, description: '装盘即可享用', time: 2 }
  234. ],
  235. cookingTime: 25,
  236. difficulty: 'medium',
  237. tips: ['根据个人喜好调整口味', '注意食材的新鲜度', '掌握好火候']
  238. }
  239. return fallbackRecipe
  240. }
  241. }
  242. // 导出配置更新函数,供外部使用
  243. export { AI_CONFIG }