Compare commits
11 Commits
url
...
dbe5a95b47
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dbe5a95b47 | ||
|
|
c1c43c1464 | ||
|
|
13d6fc228a | ||
|
|
58ce45ec92 | ||
|
|
048a9b9601 | ||
|
|
097798268b | ||
|
|
f7eb1b7048 | ||
|
|
4133b80d49 | ||
|
|
57b03436f3 | ||
|
|
836ea90145 | ||
|
|
a040b7a16a |
@@ -99,8 +99,8 @@ public enum GoodsTypeEnum
|
||||
[Price(83.7, 3, 27.9)] [DisplayName("YiXinVip 3 month", "3个月", "短期体验")] [GoodsCategory(GoodsCategoryType.Vip)]
|
||||
YiXinVip3 = 3,
|
||||
|
||||
[Price(114.5, 5, 22.9)] [DisplayName("YiXinVip 5 month", "5个月", "年度热销")] [GoodsCategory(GoodsCategoryType.Vip)]
|
||||
YiXinVip5 = 15,
|
||||
[Price(91.6, 4, 22.9)] [DisplayName("YiXinVip 4 month", "4个月", "年度热销")] [GoodsCategory(GoodsCategoryType.Vip)]
|
||||
YiXinVip5 = 14,
|
||||
|
||||
// 尊享包服务 - 需要VIP资格才能购买
|
||||
[Price(188.9, 0, 1750)]
|
||||
|
||||
@@ -642,7 +642,7 @@ public class AiGateWayManager : DomainService
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
if (responseResult.Item1=="exception")
|
||||
if (responseResult.Item1.Contains("exception"))
|
||||
{
|
||||
//兼容部分ai工具问题
|
||||
continue;
|
||||
|
||||
@@ -4,6 +4,7 @@ using Serilog.Events;
|
||||
using Yi.Abp.Web;
|
||||
|
||||
//创建日志,可使用{SourceContext}记录
|
||||
var outputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}【{SourceContext}】[{Level:u3}]{Message:lj}{NewLine}{Exception}";
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
//由于后端处理请求中,前端请求已经结束,此类日志可不记录
|
||||
.Filter.ByExcluding(log =>log.Exception?.GetType() == typeof(TaskCanceledException)||log.MessageTemplate.Text.Contains("\"message\": \"A task was canceled.\""))
|
||||
@@ -11,10 +12,15 @@ Log.Logger = new LoggerConfiguration()
|
||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore.Hosting.Diagnostics", LogEventLevel.Error)
|
||||
.MinimumLevel.Override("Quartz", LogEventLevel.Warning)
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler", LogEventLevel.Warning)
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore.Cors.Infrastructure.CorsService", LogEventLevel.Warning)
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore.Authorization.DefaultAuthorizationService", LogEventLevel.Warning)
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore.Routing.EndpointMiddleware", LogEventLevel.Warning)
|
||||
.MinimumLevel.Override("Hangfire.Server.ServerHeartbeatProcess", LogEventLevel.Warning)
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.Async(c => c.File("logs/all/log-.txt", rollingInterval: RollingInterval.Day, restrictedToMinimumLevel: LogEventLevel.Debug))
|
||||
.WriteTo.Async(c => c.File("logs/error/errorlog-.txt", rollingInterval: RollingInterval.Day, restrictedToMinimumLevel: LogEventLevel.Error))
|
||||
.WriteTo.Async(c => c.Console())
|
||||
.WriteTo.Async(c => c.File("logs/all/log-.txt", rollingInterval: RollingInterval.Day, restrictedToMinimumLevel: LogEventLevel.Debug,outputTemplate:outputTemplate))
|
||||
.WriteTo.Async(c => c.File("logs/error/errorlog-.txt", rollingInterval: RollingInterval.Day, restrictedToMinimumLevel: LogEventLevel.Error,outputTemplate:outputTemplate))
|
||||
.WriteTo.Async(c => c.Console(outputTemplate:outputTemplate))
|
||||
.CreateLogger();
|
||||
|
||||
try
|
||||
|
||||
@@ -283,7 +283,7 @@
|
||||
appRendered = true;
|
||||
checkAndHideLoader();
|
||||
}
|
||||
}, 30000);
|
||||
}, 60000);
|
||||
})();
|
||||
</script>
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ const vipRemainingDays = computed(() => {
|
||||
// VIP到期状态文本
|
||||
const vipExpireStatusText = computed(() => {
|
||||
if (!userVipStatus.value) return '';
|
||||
if (!vipExpireTime.value) return '永久VIP';
|
||||
if (!vipExpireTime.value) return '-';
|
||||
if (vipRemainingDays.value === null) return '';
|
||||
if (vipRemainingDays.value < 0) return '已过期';
|
||||
if (vipRemainingDays.value === 0) return '今日到期';
|
||||
@@ -202,7 +202,7 @@ function bindWechat() {
|
||||
{{ formatDate(vipExpireTime)?.split(' ')[0] || '-' }}
|
||||
</template>
|
||||
<template v-else>
|
||||
永久
|
||||
-
|
||||
</template>
|
||||
</div>
|
||||
<div class="stat-label">
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { useHookFetch } from 'hook-fetch/vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { ref, computed } from 'vue';
|
||||
import type { AnyObject } from 'typescript-api-pro';
|
||||
import { deleteMessages, unifiedSend } from '@/api';
|
||||
import { useModelStore } from '@/stores/modules/model';
|
||||
import { convertToApiFormat, parseStreamChunk, type UnifiedMessage } from '@/utils/apiFormatConverter';
|
||||
import type { BubbleProps } from 'vue-element-plus-x/types/Bubble';
|
||||
import type { ThinkingStatus } from 'vue-element-plus-x/types/Thinking';
|
||||
import type { UnifiedMessage } from '@/utils/apiFormatConverter';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { useHookFetch } from 'hook-fetch/vue';
|
||||
import { ref } from 'vue';
|
||||
import { unifiedSend } from '@/api';
|
||||
import { useModelStore } from '@/stores/modules/model';
|
||||
import { convertToApiFormat, parseStreamChunk } from '@/utils/apiFormatConverter';
|
||||
|
||||
export type MessageRole = 'ai' | 'user' | 'assistant' | string;
|
||||
|
||||
@@ -83,7 +84,8 @@ export function useChatSender(options: UseChatSenderOptions) {
|
||||
);
|
||||
|
||||
const latest = messages[messages.length - 1];
|
||||
if (!latest) return;
|
||||
if (!latest)
|
||||
return;
|
||||
|
||||
// 处理 token 使用情况
|
||||
if (parsed.usage) {
|
||||
@@ -99,7 +101,8 @@ export function useChatSender(options: UseChatSenderOptions) {
|
||||
latest.thinkingStatus = 'thinking';
|
||||
latest.loading = true;
|
||||
latest.thinlCollapse = true;
|
||||
if (!latest.reasoning_content) latest.reasoning_content = '';
|
||||
if (!latest.reasoning_content)
|
||||
latest.reasoning_content = '';
|
||||
latest.reasoning_content += parsed.reasoning_content;
|
||||
}
|
||||
|
||||
@@ -108,21 +111,26 @@ export function useChatSender(options: UseChatSenderOptions) {
|
||||
const thinkStart = parsed.content.includes('<think>');
|
||||
const thinkEnd = parsed.content.includes('</think>');
|
||||
|
||||
if (thinkStart) isThinking.value = true;
|
||||
if (thinkEnd) isThinking.value = false;
|
||||
if (thinkStart)
|
||||
isThinking.value = true;
|
||||
if (thinkEnd)
|
||||
isThinking.value = false;
|
||||
|
||||
if (isThinking.value) {
|
||||
latest.thinkingStatus = 'thinking';
|
||||
latest.loading = true;
|
||||
latest.thinlCollapse = true;
|
||||
if (!latest.reasoning_content) latest.reasoning_content = '';
|
||||
if (!latest.reasoning_content)
|
||||
latest.reasoning_content = '';
|
||||
latest.reasoning_content += parsed.content
|
||||
.replace('<think>', '')
|
||||
.replace('</think>', '');
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
latest.thinkingStatus = 'end';
|
||||
latest.loading = false;
|
||||
if (!latest.content) latest.content = '';
|
||||
if (!latest.content)
|
||||
latest.content = '';
|
||||
latest.content += parsed.content;
|
||||
}
|
||||
}
|
||||
@@ -144,7 +152,8 @@ export function useChatSender(options: UseChatSenderOptions) {
|
||||
textFiles: any[],
|
||||
onUpdate: (messages: MessageItem[]) => void,
|
||||
): Promise<void> {
|
||||
if (isSending.value) return;
|
||||
if (isSending.value)
|
||||
return;
|
||||
|
||||
isSending.value = true;
|
||||
currentRequestApiType.value = modelStore.currentModelInfo.modelApiType || 'Completions';
|
||||
@@ -207,7 +216,8 @@ export function useChatSender(options: UseChatSenderOptions) {
|
||||
fileContent += `<FILE_NAME>${fileItem.name}</FILE_NAME>\n`;
|
||||
fileContent += `<FILE_CONTENT>\n${fileItem.fileContent}\n</FILE_CONTENT>\n`;
|
||||
fileContent += `</ATTACHMENT_FILE>\n`;
|
||||
if (index < textFiles.length - 1) fileContent += '\n';
|
||||
if (index < textFiles.length - 1)
|
||||
fileContent += '\n';
|
||||
});
|
||||
contentArray.push({ type: 'text', text: fileContent });
|
||||
}
|
||||
@@ -225,7 +235,8 @@ export function useChatSender(options: UseChatSenderOptions) {
|
||||
baseMessage.content = contentArray.length > 1 || imageFiles.length > 0 || textFiles.length > 0
|
||||
? contentArray
|
||||
: item.content;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
baseMessage.content = (item.role === 'ai' || item.role === 'assistant') && item.content.length > 10000
|
||||
? `${item.content.substring(0, 10000)}...(内容过长,已省略)`
|
||||
: item.content;
|
||||
|
||||
@@ -20,7 +20,7 @@ const apiList = [
|
||||
}
|
||||
],
|
||||
"stream": true,
|
||||
"model": "gpt-5.3-codex"
|
||||
"model": "gpt-5.2-chat"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -148,7 +148,7 @@ async function copyText(text: string) {
|
||||
>
|
||||
<template #default>
|
||||
<div class="leading-normal text-sm">
|
||||
自 2025 年末起,AI 领域接口标准逐渐分化,原有的统一接口 <code class="bg-yellow-100 dark:bg-yellow-900 px-1 rounded">/v1/chat/completions</code> 已不再兼容所有模型。各厂商推出的新接口差异较大,接入第三方工具时,请务必根据具体模型选择正确的 API 类型。您可前往
|
||||
自 2025 年末起,AI 领域接口标准逐渐分化,原有的统一接口 <code class="bg-yellow-100 px-1 rounded">/v1/chat/completions</code> 已不再兼容所有模型。各厂商推出的新接口差异较大,接入第三方工具时,请务必根据具体模型选择正确的 API 类型。您可前往
|
||||
<router-link to="/model-library" class="text-primary font-bold hover:underline">模型库</router-link>
|
||||
查看各模型对应的 API 信息。
|
||||
</div>
|
||||
@@ -203,7 +203,7 @@ async function copyText(text: string) {
|
||||
<span class="font-bold text-sm">调用示例 (cURL)</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="code-block bg-gray-50 dark:bg-[#161b22] p-3 rounded-md border border-gray-200 dark:border-gray-700">
|
||||
<div class="code-block bg-gray-50 p-3 rounded-md border border-gray-200 ">
|
||||
<pre class="text-xs overflow-x-auto font-mono m-0"><code class="language-bash">curl {{ fullUrl }} \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer YOUR_API_KEY" \
|
||||
|
||||
@@ -127,17 +127,20 @@ export function toResponsesFormat(messages: UnifiedMessage[]): ResponsesMessage[
|
||||
* 将统一格式的消息转换为 Anthropic Claude 格式
|
||||
*/
|
||||
export function toClaudeFormat(messages: UnifiedMessage[]): { messages: ClaudeMessage[]; system?: string } {
|
||||
let systemPrompt: string | undefined;
|
||||
const claudeMessages: ClaudeMessage[] = [];
|
||||
|
||||
for (const msg of messages) {
|
||||
// Claude 的 system 消息需要单独提取
|
||||
// system 消息转换为 assistant 角色放入 messages 数组
|
||||
let role: 'user' | 'assistant';
|
||||
if (msg.role === 'system') {
|
||||
systemPrompt = typeof msg.content === 'string' ? msg.content : msg.content.map(c => c.text || '').join('');
|
||||
continue;
|
||||
role = 'assistant';
|
||||
}
|
||||
else if (msg.role === 'model') {
|
||||
role = 'assistant';
|
||||
}
|
||||
else {
|
||||
role = msg.role as 'user' | 'assistant';
|
||||
}
|
||||
|
||||
const role = msg.role === 'model' ? 'assistant' : msg.role;
|
||||
|
||||
// 处理内容格式
|
||||
let content: string | ClaudeContent[];
|
||||
@@ -181,7 +184,7 @@ export function toClaudeFormat(messages: UnifiedMessage[]): { messages: ClaudeMe
|
||||
});
|
||||
}
|
||||
|
||||
return { messages: claudeMessages, system: systemPrompt };
|
||||
return { messages: claudeMessages };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -518,16 +521,16 @@ export function convertToApiFormat(
|
||||
};
|
||||
}
|
||||
case ApiFormatType.Messages: {
|
||||
const { messages: claudeMessages, system } = toClaudeFormat(messages);
|
||||
const { messages: claudeMessages } = toClaudeFormat(messages);
|
||||
const request: any = {
|
||||
model,
|
||||
messages: claudeMessages,
|
||||
max_tokens: 32000,
|
||||
stream,
|
||||
};
|
||||
if (system) {
|
||||
request.system = system;
|
||||
}
|
||||
// if (system) {
|
||||
// request.system = system;
|
||||
// }
|
||||
return request;
|
||||
}
|
||||
case ApiFormatType.GenerateContent: {
|
||||
|
||||
1
Yi.Ai.Vue3/types/components.d.ts
vendored
1
Yi.Ai.Vue3/types/components.d.ts
vendored
@@ -54,7 +54,6 @@ declare module 'vue' {
|
||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||
ElRow: typeof import('element-plus/es')['ElRow']
|
||||
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
|
||||
ElSegmented: typeof import('element-plus/es')['ElSegmented']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElSkeleton: typeof import('element-plus/es')['ElSkeleton']
|
||||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
||||
|
||||
Reference in New Issue
Block a user