Spaces:
Sleeping
Sleeping
Junhui Ji
commited on
Commit
·
77c3f55
1
Parent(s):
9cd66d1
update openai key management
Browse files- main.py +5 -3
- static/script.js +56 -5
- static/styles.css +113 -0
main.py
CHANGED
@@ -85,6 +85,7 @@ class OptimizationRequest(BaseModel):
|
|
85 |
image_data: str
|
86 |
suggestions: List[str]
|
87 |
request_model_id: str = 'gpt-image-1'
|
|
|
88 |
|
89 |
class CaseStudyRequest(BaseModel):
|
90 |
user_input: str
|
@@ -249,7 +250,8 @@ async def optimize_design(request: OptimizationRequest, client_ip: str = None):
|
|
249 |
response = await call_openai_image_api(
|
250 |
image_data=image_data,
|
251 |
prompt=prompt,
|
252 |
-
request_model_id=request.request_model_id
|
|
|
253 |
)
|
254 |
|
255 |
return JSONResponse(response)
|
@@ -392,7 +394,7 @@ async def call_openai_api(system_prompt: str, user_content: List[Dict], request_
|
|
392 |
raise HTTPException(status_code=response.status, detail=f"OpenAI API调用失败, response: {resp}")
|
393 |
return await response.json()
|
394 |
|
395 |
-
async def call_openai_image_api(image_data: str, prompt: str, request_model_id='gpt-image-1'):
|
396 |
try:
|
397 |
# 从base64字符串中提取纯base64数据(如果包含前缀)
|
398 |
if image_data and 'base64,' in image_data:
|
@@ -420,7 +422,7 @@ async def call_openai_image_api(image_data: str, prompt: str, request_model_id='
|
|
420 |
image_file.name = "original-design.png" # 设置文件名,与JS代码一致
|
421 |
|
422 |
# 创建OpenAI客户端
|
423 |
-
client = OpenAI(api_key=OPENAI_API_IMAGE_EDIT_KEY)
|
424 |
|
425 |
# 调用图像编辑API
|
426 |
response = client.images.edit(
|
|
|
85 |
image_data: str
|
86 |
suggestions: List[str]
|
87 |
request_model_id: str = 'gpt-image-1'
|
88 |
+
openai_key: str = ''
|
89 |
|
90 |
class CaseStudyRequest(BaseModel):
|
91 |
user_input: str
|
|
|
250 |
response = await call_openai_image_api(
|
251 |
image_data=image_data,
|
252 |
prompt=prompt,
|
253 |
+
request_model_id=request.request_model_id,
|
254 |
+
openai_key=request.openai_key
|
255 |
)
|
256 |
|
257 |
return JSONResponse(response)
|
|
|
394 |
raise HTTPException(status_code=response.status, detail=f"OpenAI API调用失败, response: {resp}")
|
395 |
return await response.json()
|
396 |
|
397 |
+
async def call_openai_image_api(image_data: str, prompt: str, request_model_id='gpt-image-1', openai_key=''):
|
398 |
try:
|
399 |
# 从base64字符串中提取纯base64数据(如果包含前缀)
|
400 |
if image_data and 'base64,' in image_data:
|
|
|
422 |
image_file.name = "original-design.png" # 设置文件名,与JS代码一致
|
423 |
|
424 |
# 创建OpenAI客户端
|
425 |
+
client = OpenAI(api_key=openai_key if openai_key else OPENAI_API_IMAGE_EDIT_KEY)
|
426 |
|
427 |
# 调用图像编辑API
|
428 |
response = client.images.edit(
|
static/script.js
CHANGED
@@ -703,7 +703,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
703 |
text: uploadedText,
|
704 |
image_data: uploadedImage,
|
705 |
suggestions: suggestions,
|
706 |
-
request_model_id: 'gpt-image-1'
|
|
|
707 |
})
|
708 |
});
|
709 |
|
@@ -774,12 +775,14 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
774 |
text: uploadedText,
|
775 |
image_data: uploadedImage,
|
776 |
suggestions: suggestions,
|
777 |
-
request_model_id: 'dall-e-2'
|
|
|
778 |
})
|
779 |
});
|
780 |
-
|
781 |
-
|
782 |
-
|
|
|
783 |
}
|
784 |
|
785 |
const data = await response.json();
|
@@ -942,4 +945,52 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
942 |
return imageUrl; // 如果失败,返回原始URL
|
943 |
}
|
944 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
945 |
});
|
|
|
703 |
text: uploadedText,
|
704 |
image_data: uploadedImage,
|
705 |
suggestions: suggestions,
|
706 |
+
request_model_id: 'gpt-image-1',
|
707 |
+
openai_key: sessionStorage.getItem('userOpenaiKey') || ''
|
708 |
})
|
709 |
});
|
710 |
|
|
|
775 |
text: uploadedText,
|
776 |
image_data: uploadedImage,
|
777 |
suggestions: suggestions,
|
778 |
+
request_model_id: 'dall-e-2',
|
779 |
+
openai_key: sessionStorage.getItem('userOpenaiKey') || ''
|
780 |
})
|
781 |
});
|
782 |
+
if (response.status === 503) {
|
783 |
+
const errData = await response.json();
|
784 |
+
alert(errData.detail)
|
785 |
+
throw new Error('用户无生图权限')
|
786 |
}
|
787 |
|
788 |
const data = await response.json();
|
|
|
945 |
return imageUrl; // 如果失败,返回原始URL
|
946 |
}
|
947 |
}
|
948 |
+
|
949 |
+
// API Key Dialog functionality
|
950 |
+
const apiKeyLink = document.getElementById('apiKeyLink');
|
951 |
+
const apiKeyDialog = document.getElementById('apiKeyDialog');
|
952 |
+
const apiKeyInput = document.getElementById('apiKeyInput');
|
953 |
+
const saveApiKey = document.getElementById('saveApiKey');
|
954 |
+
const cancelApiKey = document.getElementById('cancelApiKey');
|
955 |
+
|
956 |
+
if (apiKeyLink && apiKeyDialog) {
|
957 |
+
// Show dialog when clicking the link
|
958 |
+
apiKeyLink.addEventListener('click', function(e) {
|
959 |
+
e.preventDefault();
|
960 |
+
apiKeyDialog.style.display = 'flex';
|
961 |
+
// Load existing key if available
|
962 |
+
const existingKey = sessionStorage.getItem('userOpenaiKey');
|
963 |
+
if (existingKey) {
|
964 |
+
apiKeyInput.value = existingKey;
|
965 |
+
}
|
966 |
+
});
|
967 |
+
|
968 |
+
// Save API Key
|
969 |
+
saveApiKey.addEventListener('click', function() {
|
970 |
+
const key = apiKeyInput.value.trim();
|
971 |
+
if (key) {
|
972 |
+
sessionStorage.setItem('userOpenaiKey', key);
|
973 |
+
apiKeyDialog.style.display = 'none';
|
974 |
+
// Show success message
|
975 |
+
const toast = document.getElementById('toast');
|
976 |
+
toast.textContent = 'API Key已保存';
|
977 |
+
toast.style.display = 'block';
|
978 |
+
setTimeout(() => {
|
979 |
+
toast.style.display = 'none';
|
980 |
+
}, 2000);
|
981 |
+
}
|
982 |
+
});
|
983 |
+
|
984 |
+
// Cancel button
|
985 |
+
cancelApiKey.addEventListener('click', function() {
|
986 |
+
apiKeyDialog.style.display = 'none';
|
987 |
+
});
|
988 |
+
|
989 |
+
// Close dialog when clicking outside
|
990 |
+
apiKeyDialog.addEventListener('click', function(e) {
|
991 |
+
if (e.target === apiKeyDialog) {
|
992 |
+
apiKeyDialog.style.display = 'none';
|
993 |
+
}
|
994 |
+
});
|
995 |
+
}
|
996 |
});
|
static/styles.css
CHANGED
@@ -924,4 +924,117 @@ footer {
|
|
924 |
|
925 |
@keyframes spin {
|
926 |
to { transform: rotate(360deg); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
927 |
}
|
|
|
924 |
|
925 |
@keyframes spin {
|
926 |
to { transform: rotate(360deg); }
|
927 |
+
}
|
928 |
+
|
929 |
+
/* API Key Link */
|
930 |
+
.api-key-link {
|
931 |
+
text-align: center;
|
932 |
+
margin-bottom: 20px;
|
933 |
+
}
|
934 |
+
|
935 |
+
.api-key-link a {
|
936 |
+
color: #9747FF;
|
937 |
+
font-size: 14px;
|
938 |
+
text-decoration: underline;
|
939 |
+
cursor: pointer;
|
940 |
+
}
|
941 |
+
|
942 |
+
.api-key-link a:hover {
|
943 |
+
color: #b26bff;
|
944 |
+
}
|
945 |
+
|
946 |
+
/* API Key Dialog */
|
947 |
+
.api-key-dialog {
|
948 |
+
display: none;
|
949 |
+
position: fixed;
|
950 |
+
top: 0;
|
951 |
+
left: 0;
|
952 |
+
width: 100%;
|
953 |
+
height: 100%;
|
954 |
+
background: rgba(0, 0, 0, 0.7);
|
955 |
+
z-index: 1000;
|
956 |
+
justify-content: center;
|
957 |
+
align-items: center;
|
958 |
+
}
|
959 |
+
|
960 |
+
.dialog-content {
|
961 |
+
background: #1a1a1a;
|
962 |
+
padding: 30px;
|
963 |
+
border-radius: 20px;
|
964 |
+
width: 90%;
|
965 |
+
max-width: 400px;
|
966 |
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
967 |
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
968 |
+
}
|
969 |
+
|
970 |
+
.dialog-content h3 {
|
971 |
+
margin: 0 0 15px 0;
|
972 |
+
color: #fff;
|
973 |
+
font-size: 20px;
|
974 |
+
}
|
975 |
+
|
976 |
+
.dialog-description {
|
977 |
+
color: #ccc;
|
978 |
+
margin-bottom: 15px;
|
979 |
+
font-size: 14px;
|
980 |
+
line-height: 1.5;
|
981 |
+
}
|
982 |
+
|
983 |
+
.dialog-help {
|
984 |
+
margin-bottom: 20px;
|
985 |
+
}
|
986 |
+
|
987 |
+
.dialog-help a {
|
988 |
+
color: #9747FF;
|
989 |
+
font-size: 14px;
|
990 |
+
text-decoration: none;
|
991 |
+
}
|
992 |
+
|
993 |
+
.dialog-help a:hover {
|
994 |
+
text-decoration: underline;
|
995 |
+
}
|
996 |
+
|
997 |
+
#apiKeyInput {
|
998 |
+
width: 100%;
|
999 |
+
padding: 12px;
|
1000 |
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
1001 |
+
border-radius: 8px;
|
1002 |
+
background: rgba(255, 255, 255, 0.05);
|
1003 |
+
color: #fff;
|
1004 |
+
font-size: 14px;
|
1005 |
+
margin-bottom: 20px;
|
1006 |
+
}
|
1007 |
+
|
1008 |
+
.dialog-buttons {
|
1009 |
+
display: flex;
|
1010 |
+
gap: 10px;
|
1011 |
+
justify-content: flex-end;
|
1012 |
+
}
|
1013 |
+
|
1014 |
+
.dialog-buttons button {
|
1015 |
+
padding: 8px 20px;
|
1016 |
+
border: none;
|
1017 |
+
border-radius: 8px;
|
1018 |
+
cursor: pointer;
|
1019 |
+
font-size: 14px;
|
1020 |
+
transition: all 0.3s ease;
|
1021 |
+
}
|
1022 |
+
|
1023 |
+
#saveApiKey {
|
1024 |
+
background: linear-gradient(to right, #5E33F1, #BA9EF7);
|
1025 |
+
color: white;
|
1026 |
+
}
|
1027 |
+
|
1028 |
+
#saveApiKey:hover {
|
1029 |
+
transform: translateY(-2px);
|
1030 |
+
box-shadow: 0 5px 15px rgba(94, 51, 241, 0.3);
|
1031 |
+
}
|
1032 |
+
|
1033 |
+
#cancelApiKey {
|
1034 |
+
background: rgba(255, 255, 255, 0.1);
|
1035 |
+
color: #ccc;
|
1036 |
+
}
|
1037 |
+
|
1038 |
+
#cancelApiKey:hover {
|
1039 |
+
background: rgba(255, 255, 255, 0.2);
|
1040 |
}
|