Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -1,21 +1,23 @@
|
|
1 |
-
# CHATGPT APIλ‘ λ³κ²½
|
2 |
-
|
3 |
# ββββββββββββββββββββββββββββββββ Imports ββββββββββββββββββββββββββββββββ
|
4 |
import os, json, re, logging, requests, markdown, time, io
|
5 |
from datetime import datetime
|
6 |
|
7 |
import streamlit as st
|
8 |
-
|
|
|
|
|
|
|
9 |
from gradio_client import Client
|
10 |
import pandas as pd
|
11 |
import PyPDF2 # For handling PDF files
|
12 |
|
13 |
# ββββββββββββββββββββββββββββββββ Environment Variables / Constants βββββββββββββββββββββββββ
|
14 |
-
ANTHROPIC_KEY
|
|
|
15 |
BRAVE_KEY = os.getenv("SERPHOUSE_API_KEY", "") # Keep this name
|
16 |
BRAVE_ENDPOINT = "https://api.search.brave.com/res/v1/web/search"
|
17 |
IMAGE_API_URL = "http://211.233.58.201:7896"
|
18 |
-
MAX_TOKENS =
|
19 |
|
20 |
# Blog template and style definitions (in English)
|
21 |
BLOG_TEMPLATES = {
|
@@ -45,10 +47,18 @@ EXAMPLE_TOPICS = {
|
|
45 |
logging.basicConfig(level=logging.INFO,
|
46 |
format="%(asctime)s - %(levelname)s - %(message)s")
|
47 |
|
48 |
-
# ββββββββββββββββββββββββββββββββ
|
49 |
@st.cache_resource
|
50 |
-
def
|
51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
|
53 |
# ββββββββββββββββββββββββββββββββ Blog Creation System Prompt βββββββββββββ
|
54 |
def get_system_prompt(template="ginigen", tone="professional", word_count=1750, include_search_results=False, include_uploaded_files=False) -> str:
|
@@ -514,19 +524,55 @@ def extract_image_prompt(blog_text: str, topic: str):
|
|
514 |
Analyze the blog content (blog_text) to generate a one-line English image prompt
|
515 |
related to the topic.
|
516 |
"""
|
517 |
-
|
518 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
519 |
try:
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
526 |
)
|
527 |
-
|
528 |
-
|
529 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
530 |
return f"A professional photo related to {topic}, high quality"
|
531 |
|
532 |
def md_to_html(md: str, title="Ginigen Blog"):
|
@@ -544,7 +590,8 @@ def ginigen_app():
|
|
544 |
|
545 |
# Set default session state
|
546 |
if "ai_model" not in st.session_state:
|
547 |
-
|
|
|
548 |
if "messages" not in st.session_state:
|
549 |
st.session_state.messages = []
|
550 |
if "auto_save" not in st.session_state:
|
@@ -710,7 +757,7 @@ def process_example(topic):
|
|
710 |
process_input(topic, [])
|
711 |
|
712 |
def process_input(prompt: str, uploaded_files):
|
713 |
-
# Add user's message
|
714 |
if not any(m["role"] == "user" and m["content"] == prompt for m in st.session_state.messages):
|
715 |
st.session_state.messages.append({"role": "user", "content": prompt})
|
716 |
|
@@ -725,7 +772,7 @@ def process_input(prompt: str, uploaded_files):
|
|
725 |
has_uploaded_files = bool(uploaded_files) and len(uploaded_files) > 0
|
726 |
|
727 |
try:
|
728 |
-
client =
|
729 |
|
730 |
# Prepare conversation messages
|
731 |
messages = [{"role": m["role"], "content": m["content"]} for m in st.session_state.messages]
|
@@ -752,7 +799,7 @@ def process_input(prompt: str, uploaded_files):
|
|
752 |
include_uploaded_files=has_uploaded_files
|
753 |
)
|
754 |
|
755 |
-
#
|
756 |
if file_content:
|
757 |
sys_prompt += (
|
758 |
"\n\n"
|
@@ -761,7 +808,7 @@ def process_input(prompt: str, uploaded_files):
|
|
761 |
"Ensure the file content is accurately reflected in the blog.\n"
|
762 |
)
|
763 |
|
764 |
-
#
|
765 |
if has_uploaded_files:
|
766 |
extra_user_msg = (
|
767 |
f"{prompt}\n\n"
|
@@ -770,19 +817,53 @@ def process_input(prompt: str, uploaded_files):
|
|
770 |
)
|
771 |
messages.append({"role": "user", "content": extra_user_msg})
|
772 |
|
773 |
-
#
|
774 |
-
with
|
775 |
-
|
776 |
-
|
777 |
-
|
778 |
-
|
779 |
-
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
784 |
|
785 |
-
#
|
|
|
|
|
|
|
786 |
answer_entry_saved = False
|
787 |
if st.session_state.generate_image:
|
788 |
with st.spinner("Generating image..."):
|
@@ -797,8 +878,8 @@ def process_input(prompt: str, uploaded_files):
|
|
797 |
"image_caption": cap
|
798 |
})
|
799 |
answer_entry_saved = True
|
800 |
-
|
801 |
-
# Save the answer
|
802 |
if not answer_entry_saved:
|
803 |
st.session_state.messages.append({"role": "assistant", "content": answer})
|
804 |
|
@@ -827,16 +908,6 @@ def process_input(prompt: str, uploaded_files):
|
|
827 |
except Exception as e:
|
828 |
logging.error(f"Auto-save failed: {e}")
|
829 |
|
830 |
-
except anthropic.BadRequestError as e:
|
831 |
-
error_message = str(e)
|
832 |
-
if "credit balance is too low" in error_message:
|
833 |
-
placeholder.error("β οΈ Insufficient API credits: Please top up your Anthropic API account.")
|
834 |
-
ans = "Unable to generate blog due to low API credits. Please recharge and try again."
|
835 |
-
else:
|
836 |
-
placeholder.error(f"API request error: {error_message}")
|
837 |
-
ans = f"An error occurred while calling the API: {error_message}"
|
838 |
-
st.session_state.messages.append({"role": "assistant", "content": ans})
|
839 |
-
|
840 |
except Exception as e:
|
841 |
error_message = str(e)
|
842 |
placeholder.error(f"An error occurred: {error_message}")
|
@@ -848,4 +919,4 @@ def main():
|
|
848 |
ginigen_app()
|
849 |
|
850 |
if __name__ == "__main__":
|
851 |
-
main()
|
|
|
|
|
|
|
1 |
# ββββββββββββββββββββββββββββββββ Imports ββββββββββββββββββββββββββββββββ
|
2 |
import os, json, re, logging, requests, markdown, time, io
|
3 |
from datetime import datetime
|
4 |
|
5 |
import streamlit as st
|
6 |
+
# >>> Anthropic λΆλΆ μμ
|
7 |
+
# import anthropic
|
8 |
+
from openai import OpenAI # 컀μ€ν
λνΌ(λλ λ³λ λΌμ΄λΈλ¬λ¦¬)λΌκ³ κ°μ
|
9 |
+
|
10 |
from gradio_client import Client
|
11 |
import pandas as pd
|
12 |
import PyPDF2 # For handling PDF files
|
13 |
|
14 |
# ββββββββββββββββββββββββββββββββ Environment Variables / Constants βββββββββββββββββββββββββ
|
15 |
+
# κΈ°μ‘΄ ANTHROPIC_KEY -> OPENAI_API_KEY λ‘ λ³κ²½
|
16 |
+
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "")
|
17 |
BRAVE_KEY = os.getenv("SERPHOUSE_API_KEY", "") # Keep this name
|
18 |
BRAVE_ENDPOINT = "https://api.search.brave.com/res/v1/web/search"
|
19 |
IMAGE_API_URL = "http://211.233.58.201:7896"
|
20 |
+
MAX_TOKENS = 7999
|
21 |
|
22 |
# Blog template and style definitions (in English)
|
23 |
BLOG_TEMPLATES = {
|
|
|
47 |
logging.basicConfig(level=logging.INFO,
|
48 |
format="%(asctime)s - %(levelname)s - %(message)s")
|
49 |
|
50 |
+
# ββββββββββββββββββββββββββββββββ OpenAI Client ββββββββββββββββββββββββββ
|
51 |
@st.cache_resource
|
52 |
+
def get_openai_client():
|
53 |
+
"""
|
54 |
+
컀μ€ν
OpenAI κ°μ²΄λ₯Ό μμ±νλ€κ³ κ°μ ν©λλ€.
|
55 |
+
μ€μ λ‘λ openai.api_key = OPENAI_API_KEY λ‘λ§ μ€μ νλ κ²½μ°κ° λ§μ΅λλ€.
|
56 |
+
"""
|
57 |
+
if not OPENAI_API_KEY:
|
58 |
+
raise RuntimeError("β οΈ OPENAI_API_KEY νκ²½ λ³μκ° μ€μ λμ§ μμμ΅λλ€.")
|
59 |
+
# μ¬κΈ°μλ μμλ‘μ λ€μκ³Ό κ°μ΄ μ΄κΈ°ν:
|
60 |
+
client = OpenAI(api_key=OPENAI_API_KEY)
|
61 |
+
return client
|
62 |
|
63 |
# ββββββββββββββββββββββββββββββββ Blog Creation System Prompt βββββββββββββ
|
64 |
def get_system_prompt(template="ginigen", tone="professional", word_count=1750, include_search_results=False, include_uploaded_files=False) -> str:
|
|
|
524 |
Analyze the blog content (blog_text) to generate a one-line English image prompt
|
525 |
related to the topic.
|
526 |
"""
|
527 |
+
# κΈ°μ‘΄ anthropic ν΄λΌμ΄μΈνΈ μ¬μ© -> OpenAI νΈμΆλ‘ λ체
|
528 |
+
client = get_openai_client()
|
529 |
+
|
530 |
+
system_msg = (
|
531 |
+
f"Generate a single-line English image prompt from the following text:\n"
|
532 |
+
f"Topic: {topic}\n\n"
|
533 |
+
f"---\n"
|
534 |
+
f"{blog_text}\n\n"
|
535 |
+
f"---\n"
|
536 |
+
f"Return only the prompt text, nothing else."
|
537 |
+
)
|
538 |
+
|
539 |
+
# μ€μ λ‘λ openai APIλ₯Ό μ΄λ»κ² νΈμΆνλλμ λ°λΌ λ¬λΌμ§λλ€.
|
540 |
+
# μ¬κΈ°μλ μμλ‘ client.responses.create()λ₯Ό μ¬μ©νλ€κ³ κ°μ
|
541 |
try:
|
542 |
+
response = client.responses.create(
|
543 |
+
model="gpt-4.1-mini",
|
544 |
+
input=[
|
545 |
+
{
|
546 |
+
"role": "system",
|
547 |
+
"content": [
|
548 |
+
{
|
549 |
+
"type": "input_text",
|
550 |
+
"text": system_msg
|
551 |
+
}
|
552 |
+
]
|
553 |
+
}
|
554 |
+
],
|
555 |
+
text={"format": {"type": "text"}},
|
556 |
+
temperature=1,
|
557 |
+
max_output_tokens=80,
|
558 |
+
top_p=1
|
559 |
)
|
560 |
+
# μμ: response κ°μ²΄μμ 첫 λ²μ§Έ μΆλ ₯λ§ κ°μ Έμ¨λ€κ³ κ°μ
|
561 |
+
# response ꡬ쑰λ μ¬μ© μ€μΈ λνΌμ λ°λΌ λ€λ¦
λλ€.
|
562 |
+
content = ""
|
563 |
+
if "responses" in dir(response):
|
564 |
+
# κ°μ μμ: response.responses[0].content[0].text
|
565 |
+
# λλ response["choices"][0]["text"] ννμΌ μλ μμ
|
566 |
+
first_resp = response.responses[0] # κ°μ
|
567 |
+
# λ³Έ μμλ "content" νλκ° listλ‘ μκ³ , κ·Έ μ€ [0]["text"]μ κ°μ΄ μλ€κ³ κ°μ
|
568 |
+
content = first_resp.content[0]["text"].strip()
|
569 |
+
else:
|
570 |
+
content = "A professional photo related to the topic, high quality"
|
571 |
+
|
572 |
+
return content
|
573 |
+
|
574 |
+
except Exception as e:
|
575 |
+
logging.error(f"OpenAI image prompt generation error: {e}")
|
576 |
return f"A professional photo related to {topic}, high quality"
|
577 |
|
578 |
def md_to_html(md: str, title="Ginigen Blog"):
|
|
|
590 |
|
591 |
# Set default session state
|
592 |
if "ai_model" not in st.session_state:
|
593 |
+
# κΈ°μ‘΄ anthropic λͺ¨λΈλͺ
λμ , gpt-4.1-mini
|
594 |
+
st.session_state.ai_model = "gpt-4.1-mini"
|
595 |
if "messages" not in st.session_state:
|
596 |
st.session_state.messages = []
|
597 |
if "auto_save" not in st.session_state:
|
|
|
757 |
process_input(topic, [])
|
758 |
|
759 |
def process_input(prompt: str, uploaded_files):
|
760 |
+
# Add user's message
|
761 |
if not any(m["role"] == "user" and m["content"] == prompt for m in st.session_state.messages):
|
762 |
st.session_state.messages.append({"role": "user", "content": prompt})
|
763 |
|
|
|
772 |
has_uploaded_files = bool(uploaded_files) and len(uploaded_files) > 0
|
773 |
|
774 |
try:
|
775 |
+
client = get_openai_client()
|
776 |
|
777 |
# Prepare conversation messages
|
778 |
messages = [{"role": m["role"], "content": m["content"]} for m in st.session_state.messages]
|
|
|
799 |
include_uploaded_files=has_uploaded_files
|
800 |
)
|
801 |
|
802 |
+
# νμΌ λ΄μ©μ΄ μλ€λ©΄ system promptμ μΆκ°
|
803 |
if file_content:
|
804 |
sys_prompt += (
|
805 |
"\n\n"
|
|
|
808 |
"Ensure the file content is accurately reflected in the blog.\n"
|
809 |
)
|
810 |
|
811 |
+
# μ¬μ©μκ° μ
λ ₯ν promptμ νμΌ μ°Έκ³ λ©μμ§
|
812 |
if has_uploaded_files:
|
813 |
extra_user_msg = (
|
814 |
f"{prompt}\n\n"
|
|
|
817 |
)
|
818 |
messages.append({"role": "user", "content": extra_user_msg})
|
819 |
|
820 |
+
# μ΄μ OpenAI clientλ‘ μμ²μ 보λ
λλ€.
|
821 |
+
with st.spinner("Generating blog content..."):
|
822 |
+
response = client.responses.create(
|
823 |
+
model=st.session_state.ai_model,
|
824 |
+
# OpenAI λνΌμ λ§μΆ°μ λλ΅μ μΌλ‘ μ¬κ΅¬μ±ν μμ
λλ€.
|
825 |
+
input=[
|
826 |
+
{
|
827 |
+
"role": "system",
|
828 |
+
"content": [
|
829 |
+
{
|
830 |
+
"type": "input_text",
|
831 |
+
"text": sys_prompt
|
832 |
+
}
|
833 |
+
]
|
834 |
+
},
|
835 |
+
{
|
836 |
+
"role": "user",
|
837 |
+
"content": [
|
838 |
+
{
|
839 |
+
"type": "input_text",
|
840 |
+
"text": prompt
|
841 |
+
}
|
842 |
+
]
|
843 |
+
}
|
844 |
+
# νμνλ©΄ messages μ 체λ₯Ό λ£μ μλ μμ§λ§,
|
845 |
+
# μ¬κΈ°μλ promptμ system promptλ§ λ£λ μμ
|
846 |
+
],
|
847 |
+
text={"format": {"type": "text"}},
|
848 |
+
temperature=1,
|
849 |
+
max_output_tokens=MAX_TOKENS,
|
850 |
+
top_p=1,
|
851 |
+
store=True
|
852 |
+
)
|
853 |
+
|
854 |
+
# μμμ response κ°μ²΄μμ μ΅μ’
ν
μ€νΈλ₯Ό κΊΌλ΄λ λ‘μ§
|
855 |
+
# μ€μ ꡬ쑰λ λΌμ΄λΈλ¬λ¦¬ ꡬνμ λ°λΌ λ€λ¦
λλ€
|
856 |
+
if "responses" in dir(response):
|
857 |
+
# κ°μ : response.responses[0].content[0].text νν
|
858 |
+
content_blocks = response.responses[0].content
|
859 |
+
answer = "\n".join(block["text"] for block in content_blocks if block["type"] == "output_text")
|
860 |
+
else:
|
861 |
+
answer = "Error: Unable to parse the OpenAI response."
|
862 |
|
863 |
+
# μ€νΈλ¦¬λ°μ΄ μλλ―λ‘ οΏ½οΏ½οΏ½λ²μ answer νλ ν μΆλ ₯
|
864 |
+
placeholder.markdown(answer)
|
865 |
+
|
866 |
+
# μ΄λ―Έμ§ μμ±
|
867 |
answer_entry_saved = False
|
868 |
if st.session_state.generate_image:
|
869 |
with st.spinner("Generating image..."):
|
|
|
878 |
"image_caption": cap
|
879 |
})
|
880 |
answer_entry_saved = True
|
881 |
+
|
882 |
+
# Save the answer if not saved above
|
883 |
if not answer_entry_saved:
|
884 |
st.session_state.messages.append({"role": "assistant", "content": answer})
|
885 |
|
|
|
908 |
except Exception as e:
|
909 |
logging.error(f"Auto-save failed: {e}")
|
910 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
911 |
except Exception as e:
|
912 |
error_message = str(e)
|
913 |
placeholder.error(f"An error occurred: {error_message}")
|
|
|
919 |
ginigen_app()
|
920 |
|
921 |
if __name__ == "__main__":
|
922 |
+
main()
|