feat: 支持更多类型的图片模型
This commit is contained in:
@@ -43,7 +43,7 @@ public class ImageGenerationJob : AsyncBackgroundJob<ImageGenerationJobArgs>, IT
|
|||||||
// 构建 Gemini API 请求对象
|
// 构建 Gemini API 请求对象
|
||||||
var parts = new List<object>
|
var parts = new List<object>
|
||||||
{
|
{
|
||||||
new { text = task.Prompt }
|
new { role="user",text = task.Prompt }
|
||||||
};
|
};
|
||||||
|
|
||||||
// 添加参考图(如果有)
|
// 添加参考图(如果有)
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ public static class GeminiGenerateContentAcquirer
|
|||||||
+ usage.Value.GetPath("thoughtsTokenCount").GetInt()
|
+ usage.Value.GetPath("thoughtsTokenCount").GetInt()
|
||||||
+ usage.Value.GetPath("toolUsePromptTokenCount").GetInt();
|
+ usage.Value.GetPath("toolUsePromptTokenCount").GetInt();
|
||||||
|
|
||||||
|
|
||||||
return new ThorUsageResponse
|
return new ThorUsageResponse
|
||||||
{
|
{
|
||||||
PromptTokens = inputTokens,
|
PromptTokens = inputTokens,
|
||||||
@@ -32,32 +31,43 @@ public static class GeminiGenerateContentAcquirer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取图片url,包含前缀
|
/// 获取图片 base64(包含 data:image 前缀)
|
||||||
|
/// 优先从 inlineData.data 中获取,其次从 markdown text 中解析
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="response"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string GetImagePrefixBase64(JsonElement response)
|
public static string GetImagePrefixBase64(JsonElement response)
|
||||||
{
|
{
|
||||||
// 获取 candidates[0].content.parts[0].text
|
// Step 1: 优先尝试从 candidates[0].content.parts[0].inlineData.data 获取
|
||||||
var text = response.GetPath("candidates", 0, "content", "parts", 0, "text").GetString();
|
var inlineBase64 = response
|
||||||
|
.GetPath("candidates", 0, "content", "parts", 0, "inlineData", "data")
|
||||||
|
.GetString();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(inlineBase64))
|
||||||
|
{
|
||||||
|
// 默认按 png 格式拼接前缀
|
||||||
|
return $"data:image/png;base64,{inlineBase64}";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: fallback,从 candidates[0].content.parts[0].text 中解析 markdown 图片
|
||||||
|
var text = response
|
||||||
|
.GetPath("candidates", 0, "content", "parts", 0, "text")
|
||||||
|
.GetString();
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(text))
|
if (string.IsNullOrEmpty(text))
|
||||||
{
|
{
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析 markdown 图片格式: 
|
// markdown 图片格式: 
|
||||||
// 提取括号内的 data:image/xxx;base64,xxx 部分
|
|
||||||
var startMarker = "(data:image/";
|
var startMarker = "(data:image/";
|
||||||
var startIndex = text.IndexOf(startMarker);
|
var startIndex = text.IndexOf(startMarker, StringComparison.Ordinal);
|
||||||
if (startIndex < 0)
|
if (startIndex < 0)
|
||||||
{
|
{
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从 "data:" 开始
|
|
||||||
startIndex += 1; // 跳过 "("
|
startIndex += 1; // 跳过 "("
|
||||||
var endIndex = text.IndexOf(')', startIndex);
|
var endIndex = text.IndexOf(')', startIndex);
|
||||||
if (endIndex < 0)
|
if (endIndex <= startIndex)
|
||||||
{
|
{
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ public class AiGateWayManager : DomainService
|
|||||||
{
|
{
|
||||||
throw new UserFriendlyException($"【{modelId}】模型当前版本【{modelApiType}】格式不支持");
|
throw new UserFriendlyException($"【{modelId}】模型当前版本【{modelApiType}】格式不支持");
|
||||||
}
|
}
|
||||||
// ✅ 统一处理 -nx 后缀(网关层模型规范化)
|
// ✅ 统一处理 yi- 后缀(网关层模型规范化)
|
||||||
if (!string.IsNullOrEmpty(aiModelDescribe.ModelId) &&
|
if (!string.IsNullOrEmpty(aiModelDescribe.ModelId) &&
|
||||||
aiModelDescribe.ModelId.StartsWith("yi-", StringComparison.OrdinalIgnoreCase))
|
aiModelDescribe.ModelId.StartsWith("yi-", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
@@ -1005,13 +1005,13 @@ public class AiGateWayManager : DomainService
|
|||||||
var data = await chatService.GenerateContentAsync(modelDescribe, request, cancellationToken);
|
var data = await chatService.GenerateContentAsync(modelDescribe, request, cancellationToken);
|
||||||
|
|
||||||
//解析json,获取base64字符串
|
//解析json,获取base64字符串
|
||||||
var imageBase64 = GeminiGenerateContentAcquirer.GetImagePrefixBase64(data);
|
var imagePrefixBase64 = GeminiGenerateContentAcquirer.GetImagePrefixBase64(data);
|
||||||
|
|
||||||
//远程调用上传接口,将base64转换为URL
|
//远程调用上传接口,将base64转换为URL
|
||||||
var httpClient = LazyServiceProvider.LazyGetRequiredService<IHttpClientFactory>().CreateClient();
|
var httpClient = LazyServiceProvider.LazyGetRequiredService<IHttpClientFactory>().CreateClient();
|
||||||
// var uploadUrl = $"https://ccnetcore.com/prod-api/ai-hub/ai-image/upload-base64";
|
// var uploadUrl = $"https://ccnetcore.com/prod-api/ai-hub/ai-image/upload-base64";
|
||||||
var uploadUrl = $"{ImageStoreHost}/ai-image/upload-base64";
|
var uploadUrl = $"{ImageStoreHost}/ai-image/upload-base64";
|
||||||
var content = new StringContent(JsonSerializer.Serialize(imageBase64), Encoding.UTF8, "application/json");
|
var content = new StringContent(JsonSerializer.Serialize(imagePrefixBase64), Encoding.UTF8, "application/json");
|
||||||
var uploadResponse = await httpClient.PostAsync(uploadUrl, content, cancellationToken);
|
var uploadResponse = await httpClient.PostAsync(uploadUrl, content, cancellationToken);
|
||||||
uploadResponse.EnsureSuccessStatusCode();
|
uploadResponse.EnsureSuccessStatusCode();
|
||||||
var storeUrl = await uploadResponse.Content.ReadAsStringAsync(cancellationToken);
|
var storeUrl = await uploadResponse.Content.ReadAsStringAsync(cancellationToken);
|
||||||
|
|||||||
Reference in New Issue
Block a user