Skip to main content
Glama

MCP Meeting Summary System

by W87878
article_generator.py12.5 kB
import os from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys import undetected_chromedriver as uc import time from langchain_openai import ChatOpenAI from langchain_core.output_parsers import StrOutputParser from langchain_community.callbacks import get_openai_callback from langchain_core.prompts import ChatPromptTemplate class ArticleGenerator: def __init__(self): self.user_data_dir: str = os.getenv('USER_DATA_DIR') self.profile_directory: str = os.getenv('PROFILE_DIRECTORY') self.MODEL = os.getenv('MODEL', 'gpt-4o') self.driver = None self.OPEN_API_KEY: str = os.getenv('OPEN_API_KEY') self.DIR = os.getenv('DIR') self.TEMPERATURE = float(os.getenv('TEMPERATURE', 0.7)) self.MAX_TOKENS = int(os.getenv('MAX_TOKENS', 4096)) def get_webdriver(self): for attempt in range(3): # 嘗試最多 3 次 try: options = uc.ChromeOptions() options.add_argument('--ignore-certificate-errors') options.add_argument("--disable-gpu") options.add_argument("--disable-dev-shm-usage") # options.add_argument("headless") options.add_argument(f"--user-data-dir={self.user_data_dir}") options.add_argument(f'--profile-directory={self.profile_directory}') self.driver=uc.Chrome(options=options, version_main=136, use_subprocess=True) self.driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") return self.driver except Exception as e: print(f'Error: {e}') print(f"WebDriver 啟動失敗,第 {attempt + 1} 次嘗試...") if attempt == 2: raise e time.sleep(2) # 等待 2 秒後重試 def summarize_meeting(self, text): for attempt in range(3): try: driver = self.get_webdriver() url = "https://notebooklm.google.com/" driver.get(url) time.sleep(15) # 新建專案 new_created = driver.find_element(By.XPATH, '/html/body/labs-tailwind-root/div/welcome-page/div/div[2]/div[1]/div/button/span[2]') while not new_created: time.sleep(0.1) new_created = driver.find_element(By.XPATH, '/html/body/labs-tailwind-root/div/welcome-page/div/div[2]/div[1]/div/button/span[2]') new_created.click() time.sleep(2) # 找文字區塊按鈕 text_click = driver.find_element(By.XPATH, '//*[@id="mat-mdc-chip-4"]/span[2]/span') driver.execute_script("arguments[0].scrollIntoView(true);", text_click) while not text_click: time.sleep(0.1) text_click = driver.find_element(By.XPATH, '//*[@id="mat-mdc-chip-4"]/span[2]/span') driver.execute_script("arguments[0].scrollIntoView(true);", text_click) text_click.click() time.sleep(1) # 找到 textarea 並輸入網址 text_input = driver.find_element(By.ID, 'mat-input-0') while not text_input: time.sleep(0.1) text_input = driver.find_element(By.ID, 'mat-input-0') text_input.send_keys(text) text_button = driver.find_element(By.XPATH, '//button//span[contains(text(), " Insert ")]') while not text_button: time.sleep(0.1) text_button = driver.find_element(By.XPATH, '//button//span[contains(text(), " Insert ")]') text_button.click() print(f'成功輸入文字: {text}') time.sleep(7) # 上面幾層 omnibar = driver.find_element(By.TAG_NAME, 'chat-panel').find_element(By.TAG_NAME, 'omnibar') box = omnibar.find_element(By.TAG_NAME, 'query-box') prompt_input = box.find_element(By.TAG_NAME, 'textarea') while not prompt_input.is_displayed() or not prompt_input.is_enabled(): time.sleep(0.1) prompt_input = box.find_element(By.TAG_NAME, 'textarea') j = 1 complete_prompt = "你是一位專業的技術會議紀錄助理,負責從系統開發、AI應用與Chatbot專案的會議逐字稿中,萃取並彙整出條理分明、專業且精煉的繁體中文會議摘要。請依據以下分類,並以Markdown格式、標題、條列式、加粗重點等方式,產出結構化的紀錄:一、技術討論要點 - 條列本次會議針對系統架構設計、Chatbot流程、AI模型選型與整合的核心技術討論(如API設計、資料流程、LLM/RAG部署邏輯、模型微調策略、第三方服務串接等)。如有提及API參數、資料結構、模型設定、流程圖或關鍵邏輯,請具體條列。若逐字稿資訊不足,請根據上下文合理推測,並以(推估)標註。二、系統與應用層決策 - 明確列出拍板定案的技術與應用方案(如:模型類型、開發框架、服務部署平台、前後端整合方式),並簡要補充決策依據或選型理由(如效能、成本、可擴展性等)。三、後續待辦與執行排程 - 條列尚待完成的具體項目,包含模型訓練、資料清洗、API建置、前端串接、測試/驗證流程等,並標明預計完成時程及預期產出。若有KPI或驗收標準(如自動化覆蓋率、流程時效等),請明確列出。四、任務負責人 / 技術角色 - 對應每項待辦,標註負責人或職能角色(如:後端工程師、ML Engineer、PM、QA、AI團隊)。五、技術風險與挑戰(如有)- 條列本次會議討論到的技術風險、挑戰,或需跨部門協作事項,並簡述應對策略。⚠️ 僅聚焦於技術與專案相關資訊,刪除非技術性閒聊與會議雜訊。請用專業術語、條列式、精煉描述,提升可讀性與專業度。如逐字稿資訊不足,請主動合理推估並標註(推估)。⚠️ 請勿在摘要中包含任何引用來源、段落標註或原文引文,僅呈現整理後的內容。" try: prompt_input.send_keys(complete_prompt) prompt_input.send_keys(Keys.RETURN) except Exception as e: print(f'Error: {e}') # 使用 JavaScript 強制發送鍵盤事件 driver.execute_script("arguments[0].value = arguments[1];", prompt_input, complete_prompt) # 將文字輸入到 input driver.execute_script("arguments[0].dispatchEvent(new Event('input'));", prompt_input) # 觸發 input 事件 print('等候答案') time.sleep(40) # 等待答案生成 message = driver.find_element(By.TAG_NAME, 'chat-panel').find_elements(By.TAG_NAME, 'chat-message')[j] while not message.is_displayed() or not message.is_enabled(): time.sleep(0.1) message = driver.find_element(By.TAG_NAME, 'chat-panel').find_elements(By.TAG_NAME, 'chat-message')[j] is_succesed = self.save_article_as_txt(message.text) if is_succesed: return 'summary.txt 生成成功' else: return '存檔失敗' except Exception as e: print("出現錯誤: ", str(e)) self.driver.quit() self.driver = None if self.driver: time.sleep(5) self.driver.quit() return False def convert_to_markdown_from_openai(self, language="繁體中文"): system_prompt = f""" 你是一位專業的技術會議校稿助理,負責從系統開發、AI 應用與 Chatbot 專案的概況中,萃取並彙整出條理分明、專業且精煉的繁體中文會議摘要。請依據以下分類,並以Markdown格式、標題、條列式、加粗重點等方式,再次產出結構化的紀錄,並轉為{language}: 1. 技術討論要點 條列本次會議針對系統架構設計、Chatbot流程、AI模型選型與整合的核心技術討論 (如API設計、資料流程、LLM/RAG部署邏輯、模型微調策略(如 LoRA / prompt tuning / RAG)、第三方服務串接等)。 如有提及API參數、資料結構、模型設定、流程圖或關鍵邏輯,請具體條列。 若逐字稿資訊不足,請根據上下文合理推測,並以(推估)標註。 2. 系統與應用層決策 明確列出拍板定案的技術與應用方案(如:模型類型、開發框架、服務部署平台、前後端整合方式), 並簡要補充決策依據或選型理由,例如:模型類型(GPT-4o、Claude、Gemini)、開發框架、服務部署平台(如 AWS / GCP / Azure / 自架),或前後端整合方式。 3. 後續待辦與執行排程 條列尚待完成的具體項目,包含模型訓練、資料清洗、API建置、前端串接、測試/驗證流程等,並標明預計完成時程及預期產出。 若有KPI或驗收標準(如自動化覆蓋率、流程時效等),請明確列出。 如有時程討論,請標明預計完成時間。 4. 任務負責人 / 技術角色 對應每項待辦,標註負責人或職能角色(如:後端工程師、ML Engineer、PM、QA、AI團隊)。 5. 技術風險與挑戰(如有) 條列本次會議討論到的技術風險、挑戰,或需跨部門協作事項,並簡述應對策略。 ⚠️ 僅聚焦於技術與專案相關資訊,刪除非技術性閒聊與會議雜訊。 請用專業術語、條列式、精煉描述,提升可讀性與專業度。 如逐字稿資訊不足,請主動合理推估並標註(推估)。 ⚠️ 請勿在摘要中包含任何引用來源、段落標註或原文引文,僅呈現整理後的內容。 """ # 將內容轉換為 Markdown 格式 with open(self.DIR + '/summary.txt', 'r', encoding='utf-8-sig') as file: content = file.read() with get_openai_callback() as cb: model_name = self.MODEL llm = ChatOpenAI( model_name=model_name, temperature=self.TEMPERATURE, api_key=self.OPEN_API_KEY, max_tokens=self.MAX_TOKENS) qa_prompt = ChatPromptTemplate.from_messages( [ ("system", system_prompt), ("human", "{content}"), ] ) rag_chain = ( qa_prompt | llm | StrOutputParser() ) result = rag_chain.invoke( {"content": content} ) print(f"Total Tokens: {cb.total_tokens}") print(f"Prompt Tokens: {cb.prompt_tokens}") print(f"Completion Tokens: {cb.completion_tokens}") print(f"Total Cost (USD): ${cb.total_cost}") # 將結果保存為 Markdown 文件 is_success = self.save_article_as_md(result, filename=self.DIR + '/summary.md') return is_success def save_article_as_md(self, content): # 打開或創建一個 .md 文件 try: filename = self.DIR + '/summary.md' with open(filename, 'w+', encoding='utf-8-sig') as file: # 將文章內容寫入文件 file.write(content) print(f"文章已成功保存為 {filename}") return True except Exception as e: print(f"保存文章時發生錯誤: {str(e)}") return False def save_article_as_txt(self, content): # 打開或創建一個 .txt 文件 try: filename = self.DIR + '/summary.txt' with open(filename, 'w+', encoding='utf-8-sig') as file: # 將文章內容寫入文件 file.write(content) print(f"文章已成功保存為 {filename}") return True except Exception as e: print(f"保存文章時發生錯誤: {str(e)}") return False

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/W87878/advanced_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server