Procházet zdrojové kódy

将模型配置文件提取到env

liuziting před 6 měsíci
rodič
revize
f6dfa970cf
4 změnil soubory, kde provedl 89 přidání a 50 odebrání
  1. 16 6
      .env.example
  2. 20 6
      README.md
  3. 43 34
      src/services/aiService.ts
  4. 10 4
      src/services/imageService.ts

+ 16 - 6
.env.example

@@ -1,8 +1,18 @@
-# 菜谱生成模型,默认Deepseek
-VITE_TEXT_DEEPSEEK_API_KEY=******
+# 菜谱生成模型配置(文本生成)- 零一万物(默认)
+VITE_TEXT_GENERATION_BASE_URL=https://api.lingyiwanwu.com/v1/
+VITE_TEXT_GENERATION_API_KEY=******
+VITE_TEXT_GENERATION_MODEL=yi-lightning
+VITE_TEXT_GENERATION_TEMPERATURE=0.7
+VITE_TEXT_GENERATION_TIMEOUT=300000
 
 
-# 菜谱生成模型,零一万物
-VITE_TEXT_LINGYIWANGWU_API_KEY=******
+# 菜谱生成模型配置(文本生成)- Deepseek(备选)
+# VITE_TEXT_GENERATION_BASE_URL=https://api.deepseek.com/v1/
+# VITE_TEXT_GENERATION_API_KEY=******
+# VITE_TEXT_GENERATION_MODEL=deepseek-chat
+# VITE_TEXT_GENERATION_TEMPERATURE=0.7
+# VITE_TEXT_GENERATION_TIMEOUT=300000
 
 
-# 效果图生成模型,默认bigmodel
-VITE_IMAGE_BIGMODEL_API_KEY=******
+# 图片生成模型配置
+VITE_IMAGE_GENERATION_BASE_URL=https://open.bigmodel.cn/api/paas/v4/
+VITE_IMAGE_GENERATION_API_KEY=******
+VITE_IMAGE_GENERATION_MODEL=cogview-3-flash

+ 20 - 6
README.md

@@ -114,7 +114,8 @@
 -   **开发语言:** TypeScript 5.3+
 -   **开发语言:** TypeScript 5.3+
 -   **样式方案:** Tailwind CSS 3.4+
 -   **样式方案:** Tailwind CSS 3.4+
 -   **构建工具:** Vite 5.0+
 -   **构建工具:** Vite 5.0+
--   **AI 服务:** DeepSeek Chat API + 智谱 AI GLM-4-Flash
+-   **AI 服务:** 零一万物 Yi-Lightning(菜谱生成) + 智谱 AI CogView-3-Flash(图片生成)
+-   **备选方案:** DeepSeek Chat API(菜谱生成)
 -   **部署平台:** Netlify 自动化部署
 -   **部署平台:** Netlify 自动化部署
 
 
 ## 🎯 快速开始
 ## 🎯 快速开始
@@ -147,11 +148,24 @@ npm run dev
 ### 环境变量配置
 ### 环境变量配置
 
 
 ```env
 ```env
-# DeepSeek API 菜谱生成配置
-VITE_TEXT_DEEPSEEK_API_KEY=your_deepseek_api_key_here
-
-# Bigmodel API 图像生成配置
-VITE_IMAGE_BIGMODEL_API_KEY=your_image_api_key_here
+# 菜谱生成模型配置(文本生成)- 零一万物(默认)
+VITE_TEXT_GENERATION_BASE_URL=https://api.lingyiwanwu.com/v1/
+VITE_TEXT_GENERATION_API_KEY=your_text_api_key_here
+VITE_TEXT_GENERATION_MODEL=yi-lightning
+VITE_TEXT_GENERATION_TEMPERATURE=0.7
+VITE_TEXT_GENERATION_TIMEOUT=300000
+
+# 菜谱生成模型配置(文本生成)- Deepseek(备选)
+# VITE_TEXT_GENERATION_BASE_URL=https://api.deepseek.com/v1/
+# VITE_TEXT_GENERATION_API_KEY=your_deepseek_api_key_here
+# VITE_TEXT_GENERATION_MODEL=deepseek-chat
+# VITE_TEXT_GENERATION_TEMPERATURE=0.7
+# VITE_TEXT_GENERATION_TIMEOUT=300000
+
+# 图片生成模型配置
+VITE_IMAGE_GENERATION_BASE_URL=https://open.bigmodel.cn/api/paas/v4/
+VITE_IMAGE_GENERATION_API_KEY=your_image_api_key_here
+VITE_IMAGE_GENERATION_MODEL=cogview-3-flash
 ```
 ```
 
 
 ## 📖 使用指南
 ## 📖 使用指南

+ 43 - 34
src/services/aiService.ts

@@ -1,25 +1,26 @@
 import axios from 'axios'
 import axios from 'axios'
-import type { Recipe, CuisineType, NutritionAnalysis, WinePairing, SauceRecipe, SaucePreference, CustomSauceRequest, FortuneResult, DailyFortuneParams, MoodFortuneParams, CoupleFortuneParams, NumberFortuneParams } from '@/types'
-
-// AI服务配置 - 从环境变量读取
+import type {
+    Recipe,
+    CuisineType,
+    NutritionAnalysis,
+    WinePairing,
+    SauceRecipe,
+    SaucePreference,
+    CustomSauceRequest,
+    FortuneResult,
+    DailyFortuneParams,
+    MoodFortuneParams,
+    CoupleFortuneParams,
+    NumberFortuneParams
+} from '@/types'
+
+// AI服务配置 - 从环境变量读取(菜谱生成模型配置)
 const AI_CONFIG = {
 const AI_CONFIG = {
-    // baseURL: 'https://api.deepseek.com/v1/',
-    // apiKey: import.meta.env.VITE_TEXT_DEEPSEEK_API_KEY,
-    // model: 'deepseek-chat',
-    // temperature: 0.7,
-    // timeout: 300000
-
-    // baseURL: 'https://open.bigmodel.cn/api/paas/v4/',
-    // apiKey: import.meta.env.VITE_IMAGE_BIGMODEL_API_KEY,
-    // model: 'GLM-4-Flash-250414',
-    // temperature: 0.9,
-    // timeout: 300000
-
-    baseURL: 'https://api.lingyiwanwu.com/v1/',
-    apiKey: import.meta.env.VITE_TEXT_LINGYIWANGWU_API_KEY,
-    model: 'yi-lightning',
-    temperature: 0.7,
-    timeout: 300000
+    baseURL: import.meta.env.VITE_TEXT_GENERATION_BASE_URL || 'https://api.lingyiwanwu.com/v1/',
+    apiKey: import.meta.env.VITE_TEXT_GENERATION_API_KEY,
+    model: import.meta.env.VITE_TEXT_GENERATION_MODEL || 'yi-lightning',
+    temperature: Number(import.meta.env.VITE_TEXT_GENERATION_TEMPERATURE) || 0.7,
+    timeout: Number(import.meta.env.VITE_TEXT_GENERATION_TIMEOUT) || 300000
 }
 }
 
 
 // 创建axios实例
 // 创建axios实例
@@ -187,8 +188,9 @@ export const generateTableMenu = async (config: {
 - 营养搭配:${nutritionText}`
 - 营养搭配:${nutritionText}`
 
 
         if (config.customDishes.length > 0) {
         if (config.customDishes.length > 0) {
-            prompt += `\n- ${config.flexibleCount ? '优先考虑的菜品' : '必须包含的菜品'}:${config.customDishes.join('、')}${config.flexibleCount ? '(可以作为参考,根据搭配需要决定是否全部包含)' : '(请确保这些菜品都包含在菜单中)'
-                }`
+            prompt += `\n- ${config.flexibleCount ? '优先考虑的菜品' : '必须包含的菜品'}:${config.customDishes.join('、')}${
+                config.flexibleCount ? '(可以作为参考,根据搭配需要决定是否全部包含)' : '(请确保这些菜品都包含在菜单中)'
+            }`
         }
         }
 
 
         if (config.customRequirement) {
         if (config.customRequirement) {
@@ -782,7 +784,8 @@ export const generateDishRecipeByName = async (dishName: string): Promise<Recipe
             messages: [
             messages: [
                 {
                 {
                     role: 'system',
                     role: 'system',
-                    content: '你是一位经验丰富的中华料理大师,精通各种菜系的制作方法。请根据用户提供的菜名,生成详细、实用的制作教程。请严格按照JSON格式返回,不要包含任何其他文字。请务必用中文回答。'
+                    content:
+                        '你是一位经验丰富的中华料理大师,精通各种菜系的制作方法。请根据用户提供的菜名,生成详细、实用的制作教程。请严格按照JSON格式返回,不要包含任何其他文字。请务必用中文回答。'
                 },
                 },
                 {
                 {
                     role: 'user',
                     role: 'user',
@@ -881,7 +884,8 @@ export const generateSauceRecipe = async (sauceName: string): Promise<SauceRecip
             messages: [
             messages: [
                 {
                 {
                     role: 'system',
                     role: 'system',
-                    content: '你是一位专业的酱料制作大师,精通各种传统和创新酱料的制作方法。请根据用户提供的酱料名称,生成详细、实用的制作教程。请严格按照JSON格式返回,不要包含任何其他文字。请务必用中文回答。'
+                    content:
+                        '你是一位专业的酱料制作大师,精通各种传统和创新酱料的制作方法。请根据用户提供的酱料名称,生成详细、实用的制作教程。请严格按照JSON格式返回,不要包含任何其他文字。请务必用中文回答。'
                 },
                 },
                 {
                 {
                     role: 'user',
                     role: 'user',
@@ -951,9 +955,7 @@ export const recommendSauces = async (preferences: SaucePreference): Promise<str
         }
         }
 
 
         const useCaseText = preferences.useCase.map(uc => (useCaseMap as Record<string, string>)[uc] || uc).join('、')
         const useCaseText = preferences.useCase.map(uc => (useCaseMap as Record<string, string>)[uc] || uc).join('、')
-        const ingredientsText = preferences.availableIngredients.length > 0
-            ? preferences.availableIngredients.join('、')
-            : '无特殊要求'
+        const ingredientsText = preferences.availableIngredients.length > 0 ? preferences.availableIngredients.join('、') : '无特殊要求'
 
 
         const prompt = `请根据以下用户偏好推荐合适的酱料:
         const prompt = `请根据以下用户偏好推荐合适的酱料:
 
 
@@ -1221,7 +1223,8 @@ export const generateDailyFortune = async (params: DailyFortuneParams): Promise<
             messages: [
             messages: [
                 {
                 {
                     role: 'system',
                     role: 'system',
-                    content: '你是一位神秘而智慧的料理占卜师,精通星座学、生肖学和美食文化。你的话语充满神秘色彩,善于将占卜元素与美食完美结合。请严格按照JSON格式返回,不要包含任何其他文字。请务必用中文回答。'
+                    content:
+                        '你是一位神秘而智慧的料理占卜师,精通星座学、生肖学和美食文化。你的话语充满神秘色彩,善于将占卜元素与美食完美结合。请严格按照JSON格式返回,不要包含任何其他文字。请务必用中文回答。'
                 },
                 },
                 {
                 {
                     role: 'user',
                     role: 'user',
@@ -1301,7 +1304,8 @@ export const generateMoodCooking = async (params: MoodFortuneParams): Promise<Fo
             messages: [
             messages: [
                 {
                 {
                     role: 'system',
                     role: 'system',
-                    content: '你是一位温暖而智慧的情感治愈师,深谙美食与情感的关系。你善于通过菜品来抚慰人心,话语温暖治愈。请严格按照JSON���式返回,不要包含任何其他文字。请务必用中文回答。'
+                    content:
+                        '你是一位温暖而智慧的情感治愈师,深谙美食与情感的关系。你善于通过菜品来抚慰人心,话语温暖治愈。请严格按照JSON���式返回,不要包含任何其他文字。请务必用中文回答。'
                 },
                 },
                 {
                 {
                     role: 'user',
                     role: 'user',
@@ -1385,7 +1389,8 @@ export const generateCoupleCooking = async (params: CoupleFortuneParams): Promis
             messages: [
             messages: [
                 {
                 {
                     role: 'system',
                     role: 'system',
-                    content: '你是一位精通人际关系和美食文化的占卜师,善于分析人与人之间的默契和缘分。你的话语充满智慧和温暖。请严格按照JSON格式返回,不要包含任何其他文字。请务必用中文回答。'
+                    content:
+                        '你是一位精通人际关系和美食文化的占卜师,善于分析人与人之间的默契和缘分。你的话语充满智慧和温暖。请严格按照JSON格式返回,不要包含任何其他文字。请务必用中文回答。'
                 },
                 },
                 {
                 {
                     role: 'user',
                     role: 'user',
@@ -1437,7 +1442,7 @@ export const generateCoupleCooking = async (params: CoupleFortuneParams): Promis
 export const generateNumberFortune = async (params: NumberFortuneParams): Promise<FortuneResult> => {
 export const generateNumberFortune = async (params: NumberFortuneParams): Promise<FortuneResult> => {
     try {
     try {
         const numberSource = params.isRandom ? '随机生成' : '用户选择'
         const numberSource = params.isRandom ? '随机生成' : '用户选择'
-        
+
         const prompt = `你是一位精通数字占卜的料理大师,请根据幸运数字推荐菜品:
         const prompt = `你是一位精通数字占卜的料理大师,请根据幸运数字推荐菜品:
 
 
 幸运数字:${params.number}
 幸运数字:${params.number}
@@ -1464,7 +1469,8 @@ export const generateNumberFortune = async (params: NumberFortuneParams): Promis
             messages: [
             messages: [
                 {
                 {
                     role: 'system',
                     role: 'system',
-                    content: '你是一位精通数字学和美食文化的神秘占卜师,善于解读数字的深层含义并与菜品联系。你的话语充满神秘和智慧。请严格按照JSON格式返回,不要包含任何其他文字。请务必用中文回答。'
+                    content:
+                        '你是一位精通数字学和美食文化的神秘占卜师,善于解读数字的深层含义并与菜品联系。你的话语充满神秘和智慧。请严格按照JSON格式返回,不要包含任何其他文字。请务必用中文回答。'
                 },
                 },
                 {
                 {
                     role: 'user',
                     role: 'user',
@@ -1563,7 +1569,10 @@ export const chatStream = async (
             buffer = parts.pop() || ''
             buffer = parts.pop() || ''
 
 
             for (const part of parts) {
             for (const part of parts) {
-                const lines = part.split('\n').map(l => l.trim()).filter(Boolean)
+                const lines = part
+                    .split('\n')
+                    .map(l => l.trim())
+                    .filter(Boolean)
                 for (const line of lines) {
                 for (const line of lines) {
                     if (!line.startsWith('data:')) continue
                     if (!line.startsWith('data:')) continue
                     const data = line.slice(5).trim()
                     const data = line.slice(5).trim()
@@ -1594,4 +1603,4 @@ export const chatStream = async (
         else console.error('chatStream error:', err)
         else console.error('chatStream error:', err)
         throw err
         throw err
     }
     }
-}
+}

+ 10 - 4
src/services/imageService.ts

@@ -1,7 +1,13 @@
 import type { Recipe } from '@/types'
 import type { Recipe } from '@/types'
 
 
-const API_KEY = import.meta.env.VITE_IMAGE_BIGMODEL_API_KEY
-const API_URL = 'https://open.bigmodel.cn/api/paas/v4/images/generations'
+// 图片生成模型配置 - 从环境变量读取
+const IMAGE_CONFIG = {
+    apiKey: import.meta.env.VITE_IMAGE_GENERATION_API_KEY,
+    baseURL: import.meta.env.VITE_IMAGE_GENERATION_BASE_URL || 'https://open.bigmodel.cn/api/paas/v4/',
+    model: import.meta.env.VITE_IMAGE_GENERATION_MODEL || 'cogview-3-flash'
+}
+
+const API_URL = `${IMAGE_CONFIG.baseURL}images/generations`
 
 
 export interface GeneratedImage {
 export interface GeneratedImage {
     url: string
     url: string
@@ -19,10 +25,10 @@ export const generateRecipeImage = async (recipe: Recipe): Promise<GeneratedImag
             method: 'POST',
             method: 'POST',
             headers: {
             headers: {
                 'Content-Type': 'application/json',
                 'Content-Type': 'application/json',
-                Authorization: `Bearer ${API_KEY}`
+                Authorization: `Bearer ${IMAGE_CONFIG.apiKey}`
             },
             },
             body: JSON.stringify({
             body: JSON.stringify({
-                model: 'cogview-3-flash',
+                model: IMAGE_CONFIG.model,
                 prompt: prompt,
                 prompt: prompt,
                 size: `${sizeToUse.width}x${sizeToUse.height}`,
                 size: `${sizeToUse.width}x${sizeToUse.height}`,
                 n: 1,
                 n: 1,