Spaces:
Runtime error
Runtime error
| import os | |
| import json | |
| import re | |
| import streamlit as st | |
| from openai import OpenAI | |
| from googleapiclient.discovery import build | |
| from google.oauth2 import service_account | |
| st.set_page_config( | |
| page_title="νμλ‘ μμ½ + μΊλ¦°λ λ±λ‘", | |
| page_icon="π ", | |
| layout="wide" | |
| ) | |
| SCOPES = ["https://www.googleapis.com/auth/calendar"] | |
| def get_openai_client(): | |
| api_key = os.environ.get("OPENAI_API_KEY") | |
| if not api_key: | |
| st.error("OPENAI_API_KEY Secretμ΄ μ€μ λμ΄ μμ§ μμ΅λλ€.") | |
| st.stop() | |
| return OpenAI(api_key=api_key) | |
| def get_calendar_service(): | |
| service_account_json = os.environ.get("GOOGLE_SERVICE_ACCOUNT_JSON") | |
| if not service_account_json: | |
| st.error("GOOGLE_SERVICE_ACCOUNT_JSON Secretμ΄ μ€μ λμ΄ μμ§ μμ΅λλ€.") | |
| st.stop() | |
| try: | |
| service_account_info = json.loads(service_account_json) | |
| except json.JSONDecodeError: | |
| st.error("GOOGLE_SERVICE_ACCOUNT_JSON κ°μ΄ μ¬λ°λ₯Έ JSON νμμ΄ μλλλ€.") | |
| st.stop() | |
| creds = service_account.Credentials.from_service_account_info( | |
| service_account_info, | |
| scopes=SCOPES | |
| ) | |
| return build("calendar", "v3", credentials=creds) | |
| def clean_json_text(text): | |
| text = text.strip() | |
| text = re.sub(r"^```json", "", text) | |
| text = re.sub(r"^```", "", text) | |
| text = re.sub(r"```$", "", text) | |
| return text.strip() | |
| def summarize_meeting(client, meeting_text): | |
| prompt = f""" | |
| λ€μ νμλ‘μ κ°λ΅νκ² μμ½ν΄μ€. | |
| λ무 κΈΈκ² μ°μ§ λ§κ³ , μλ νμμΌλ‘λ§ μ 리ν΄. | |
| νμ: | |
| 1. νμ μ£Όμ : | |
| 2. μΌμ: | |
| 3. μ₯μ: | |
| 4. μ°Έμμ: | |
| 5. μ£Όμ λ Όμ λ΄μ©: | |
| 6. μ£Όμ μΌμ : | |
| 7. λ΄λΉ μ 무: | |
| νμλ‘: | |
| {meeting_text} | |
| """ | |
| response = client.responses.create( | |
| model="gpt-4o-mini", | |
| input=prompt | |
| ) | |
| return response.output_text | |
| def extract_calendar_events(client, meeting_text): | |
| prompt = f""" | |
| λ€μ νμλ‘μμ Google Calendarμ λ±λ‘ν μΌμ λ§ JSON λ°°μ΄λ‘ μΆμΆν΄μ€. | |
| λ°λμ JSON λ°°μ΄λ§ μΆλ ₯ν΄. | |
| μ€λͺ λ¬Έμ₯ κΈμ§. | |
| λ§ν¬λ€μ΄ μ½λλΈλ‘ κΈμ§. | |
| 쑰건: | |
| - λ μ§κ° λͺ νν μΌμ λ§ μΆμΆ | |
| - μκ°μ΄ μμΌλ©΄ μμμκ°μ 09:00, μ’ λ£μκ°μ 10:00 | |
| - λ μ§ νμμ YYYY-MM-DD | |
| - μκ° νμμ HH:MM | |
| - νκ΅ μκ° κΈ°μ€ | |
| - μ₯μκ° μμΌλ©΄ λΉ λ¬Έμμ΄ | |
| - λ΄λΉμκ° μμΌλ©΄ λΉ λ¬Έμμ΄ | |
| - νμ μ체 μΌμ λ λ μ§μ μκ°μ΄ μμΌλ©΄ ν¬ν¨ | |
| μΆλ ₯ νμ: | |
| [ | |
| {{ | |
| "μ λͺ©": "", | |
| "λ μ§": "YYYY-MM-DD", | |
| "μμμκ°": "HH:MM", | |
| "μ’ λ£μκ°": "HH:MM", | |
| "μ₯μ": "", | |
| "μ€λͺ ": "", | |
| "λ΄λΉμ": "" | |
| }} | |
| ] | |
| νμλ‘: | |
| {meeting_text} | |
| """ | |
| response = client.responses.create( | |
| model="gpt-4o-mini", | |
| input=prompt | |
| ) | |
| raw = clean_json_text(response.output_text) | |
| try: | |
| return json.loads(raw) | |
| except json.JSONDecodeError: | |
| st.error("μΌμ JSON λ³ν μ€ν¨") | |
| st.text(raw) | |
| return [] | |
| def add_events_to_calendar(events, calendar_id): | |
| service = get_calendar_service() | |
| created_links = [] | |
| for item in events: | |
| date = item.get("λ μ§") | |
| start_time = item.get("μμμκ°", "09:00") | |
| end_time = item.get("μ’ λ£μκ°", "10:00") | |
| if not date: | |
| continue | |
| event = { | |
| "summary": item.get("μ λͺ©", "νμ μΌμ "), | |
| "location": item.get("μ₯μ", ""), | |
| "description": f"λ΄λΉμ: {item.get('λ΄λΉμ', '')}\n\n{item.get('μ€λͺ ', '')}", | |
| "start": { | |
| "dateTime": f"{date}T{start_time}:00", | |
| "timeZone": "Asia/Seoul", | |
| }, | |
| "end": { | |
| "dateTime": f"{date}T{end_time}:00", | |
| "timeZone": "Asia/Seoul", | |
| }, | |
| } | |
| created_event = service.events().insert( | |
| calendarId=calendar_id, | |
| body=event | |
| ).execute() | |
| created_links.append(created_event.get("htmlLink")) | |
| return created_links | |
| st.title("νμλ‘ μμ½ + Google Calendar μΌμ λ±λ‘") | |
| st.info("txt νμλ‘μ μ λ‘λνλ©΄ λ΄μ©μ μμ½νκ³ λ μ§κ° μλ μΌμ μ Google Calendarμ λ±λ‘ν©λλ€.") | |
| calendar_id = st.text_input( | |
| "Google Calendar ID", | |
| value="primary", | |
| help="κΈ°λ³Έ μΊλ¦°λλ primaryλ₯Ό κ·Έλλ‘ λμΈμ." | |
| ) | |
| uploaded_file = st.file_uploader("νμλ‘ txt νμΌ μ λ‘λ", type=["txt"]) | |
| if uploaded_file is not None: | |
| meeting_text = uploaded_file.read().decode("utf-8") | |
| st.subheader("μ λ‘λν νμλ‘") | |
| st.text_area("νμλ‘ λ΄μ©", meeting_text, height=250) | |
| client = get_openai_client() | |
| if st.button("1. νμλ‘ μμ½ λ° μΌμ μΆμΆ"): | |
| with st.spinner("νμλ‘μ λΆμνλ μ€μ λλ€..."): | |
| summary = summarize_meeting(client, meeting_text) | |
| events = extract_calendar_events(client, meeting_text) | |
| st.session_state["summary"] = summary | |
| st.session_state["events"] = events | |
| if "summary" in st.session_state: | |
| st.subheader("νμλ‘ μμ½") | |
| st.write(st.session_state["summary"]) | |
| if "events" in st.session_state: | |
| st.subheader("μΆμΆλ μΌμ ") | |
| events = st.session_state["events"] | |
| if len(events) == 0: | |
| st.warning("λ±λ‘ν μΌμ μ΄ μμ΅λλ€.") | |
| else: | |
| st.dataframe(events, use_container_width=True) | |
| if st.button("2. Google Calendarμ μΌμ λ±λ‘"): | |
| with st.spinner("Google Calendarμ λ±λ‘νλ μ€μ λλ€..."): | |
| links = add_events_to_calendar(events, calendar_id) | |
| st.success(f"μ΄ {len(links)}κ° μΌμ λ±λ‘ μλ£") | |
| for link in links: | |
| st.write(link) | |
| else: | |
| st.warning("νμλ‘ txt νμΌμ μ λ‘λνμΈμ.") |