diff --git a/AI_Web_Scraper/README.md b/AI_Web_Scraper/README.md index 707b0dd..566e346 100644 --- a/AI_Web_Scraper/README.md +++ b/AI_Web_Scraper/README.md @@ -6,13 +6,13 @@ - Hugging Face 모델 (jxm/gpt-oss-20b-base)을 사용하여 AI 에이전트 실행 - 웹 크롤링을 통한 정보 수집 -- 수집된 데이터의 Google Drive 저장 +- 수집된 데이터의 Google Drive 저장 (마운트 방식 기본, API 선택) - Colab Pro 환경에서 A100 GPU 활용 ## 요구사항 - Python 3.8 이상 -- Google Drive API 인증 파일 (credentials.json) +- (옵션) Google Drive API 인증 파일 (credentials.json) - Colab Pro 계정 (A100 GPU 지원) ## 설치 방법 @@ -23,15 +23,18 @@ pip install -r requirements.txt ## 설정 -1. `config.json` 파일에서 다음 항목들을 설정하세요: - - `google_drive_folder_id`: 데이터를 저장할 Google Drive 폴더 ID - - `google_credentials_path`: Google API 인증 파일 경로 +1. `config.json` 파일 설정: + - `data_storage.drive_mount_path`: 기본 저장 경로 (마운트 방식) + - (옵션) `google_drive_folder_id`: Google Drive API 업로드 대상 폴더 ID + - (옵션) `google_credentials_path`: Google API 인증 파일 경로 -2. Google Drive API 설정: +2. (옵션) Google Drive API 설정: - Google Cloud Console에서 Drive API 활성화 - OAuth 2.0 클라이언트 ID 생성 - credentials.json 파일 다운로드 + credentials.json 또는 folder_id가 없으면 API 업로드는 자동 비활성화되고, 마운트 방식 저장만 사용됩니다. + ## 실행 방법 자세한 실행 방법은 `run_guide.md` 파일을 참고하세요. diff --git a/AI_Web_Scraper/ai_agent.py b/AI_Web_Scraper/ai_agent.py index 986ed02..59314c7 100644 --- a/AI_Web_Scraper/ai_agent.py +++ b/AI_Web_Scraper/ai_agent.py @@ -28,9 +28,28 @@ class AIAgent: # 도구들 초기화 self.web_scraper = WebScraper(config_path) - self.drive_uploader = GoogleDriveUploader(config_path) self.simple_saver = SimpleDriveSaver(self.config['data_storage']['drive_mount_path']) + # Google Drive API는 선택 사항: 자격증명 파일이 존재할 때만 활성화 + self.drive_uploader = None + try: + drive_folder_id = self.config.get('google_drive_folder_id', '').strip() + creds_path = self.config.get('google_credentials_path', '').strip() + has_valid_folder = bool(drive_folder_id) and drive_folder_id != 'YOUR_GOOGLE_DRIVE_FOLDER_ID' + has_creds_file = bool(creds_path) and __import__('os').path.isfile(creds_path) + if has_valid_folder and has_creds_file: + self.drive_uploader = GoogleDriveUploader(config_path) + else: + reason = [] + if not has_valid_folder: + reason.append('folder_id 미설정') + if not has_creds_file: + reason.append('credentials 파일 없음') + print(f"Google Drive API 비활성화 ({', '.join(reason)}) — SimpleDriveSaver만 사용") + except Exception as e: + # 어떤 이유로든 초기화 실패 시 API 도구는 비활성화하고 계속 진행 + print(f"Google Drive API 초기화 실패: {e} — SimpleDriveSaver만 사용") + # LangChain 도구 정의 self.tools = [ Tool( @@ -38,11 +57,6 @@ class AIAgent: func=self.scrape_web, description="웹사이트에서 정보를 수집합니다. URL을 입력하세요." ), - Tool( - name="GoogleDriveUploader", - func=self.upload_to_drive_api, - description="Google Drive API를 사용하여 데이터를 업로드합니다. 데이터와 파일명을 입력하세요." - ), Tool( name="SimpleDriveSaver", func=self.save_to_drive_simple, @@ -50,6 +64,16 @@ class AIAgent: ) ] + # Google Drive API 도구는 사용 가능할 때만 추가 + if self.drive_uploader is not None: + self.tools.append( + Tool( + name="GoogleDriveUploader", + func=self.upload_to_drive_api, + description="Google Drive API를 사용하여 데이터를 업로드합니다. 데이터(JSON)|파일명 형식으로 입력하세요." + ) + ) + # 메모리 self.memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True) diff --git a/AI_Web_Scraper/google_drive_uploader.py b/AI_Web_Scraper/google_drive_uploader.py index 8c61049..b240379 100644 --- a/AI_Web_Scraper/google_drive_uploader.py +++ b/AI_Web_Scraper/google_drive_uploader.py @@ -22,10 +22,18 @@ class GoogleDriveUploader: """ Google Drive API 인증 """ + # 자격증명 파일 존재 여부 확인 (명시적으로 친절한 메시지 제공) + if not self.creds_path or not os.path.isfile(self.creds_path): + raise FileNotFoundError( + f"Google Drive API 자격증명 파일을 찾을 수 없습니다: {self.creds_path}.\n" + f"config.json의 'google_credentials_path'를 올바른 credentials.json 경로로 설정하거나, API 업로드를 사용하지 마세요." + ) + + token_path = os.path.join(os.path.dirname(self.creds_path) or '.', 'token.json') creds = None - if os.path.exists('token.json'): - creds = Credentials.from_authorized_user_file('token.json', self.scopes) + if os.path.exists(token_path): + creds = Credentials.from_authorized_user_file(token_path, self.scopes) if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: @@ -35,7 +43,7 @@ class GoogleDriveUploader: self.creds_path, self.scopes) creds = flow.run_local_server(port=0) - with open('token.json', 'w') as token: + with open(token_path, 'w') as token: token.write(creds.to_json()) self.service = build('drive', 'v3', credentials=creds) @@ -44,6 +52,9 @@ class GoogleDriveUploader: """ 파일을 Google Drive에 업로드 """ + if self.service is None: + raise RuntimeError('Google Drive API가 초기화되지 않았습니다. credentials.json과 folder_id를 설정하세요.') + if file_name is None: file_name = os.path.basename(file_path) @@ -87,6 +98,9 @@ class GoogleDriveUploader: """ 폴더 내 파일 목록 조회 """ + if self.service is None: + raise RuntimeError('Google Drive API가 초기화되지 않았습니다. credentials.json과 folder_id를 설정하세요.') + try: results = self.service.files().list( q=f"'{self.folder_id}' in parents", diff --git a/AI_Web_Scraper/run_guide.md b/AI_Web_Scraper/run_guide.md index 877a4f5..7a8cfe0 100644 --- a/AI_Web_Scraper/run_guide.md +++ b/AI_Web_Scraper/run_guide.md @@ -194,6 +194,16 @@ os.environ["HF_TOKEN"] = "hf_********************************" ``` 또는 양자화된/경량화된 공개 모델을 사용하면 메모리 요구량이 크게 줄어듭니다. +### 6.4 Google Drive API 인증 오류 (credentials.json 없음) + +- 기본 동작은 Google Drive 마운트 기반 저장(SimpleDriveSaver)입니다. 이 방법은 API 자격증명이 필요하지 않습니다. +- `config.json`의 `google_credentials_path`가 가리키는 `credentials.json` 파일이 없거나, `google_drive_folder_id`가 기본값이라면 Google Drive API 업로드 도구는 자동으로 비활성화되고, 마운트 저장만 사용합니다. +- Google Drive API 업로드가 필요하다면: + 1) Google Cloud Console에서 OAuth 2.0 클라이언트 ID(데스크톱)를 만들고 JSON을 다운로드 + 2) 프로젝트가 접근 가능한 경로에 파일을 두고 `config.json`의 `google_credentials_path`를 해당 경로로 설정 + 3) 업로드 대상 폴더의 ID를 `google_drive_folder_id`에 설정 + 4) 첫 실행 시 브라우저 인증을 완료하면 `token.json`이 같은 폴더에 생성됩니다. + ## 7. 확장 및 커스터마이징 ### 7.1 새로운 도구 추가