#!/usr/local/bin/python3 # -*- coding: utf-8 -*- import uuid import time import os import logging import logging.handlers import requests import gradio as gr import simplejson as json import oss2 LOGGER = logging.getLogger('skybox') HANDLER = logging.handlers.RotatingFileHandler( './logs/skybox.log', mode='a', maxBytes=20 * 1000 * 1000, backupCount=5, encoding='utf-8') FORMATTER = logging.Formatter('%(asctime)s - %(funcName)s - %(lineno)d - %(levelname)s - %(message)s') HANDLER.setFormatter(FORMATTER) LOGGER.propagate = 0 LOGGER.addHandler(HANDLER) LOGGER.setLevel(logging.DEBUG) CSS = '.gradio-container a {color:#b7adf4 !important}' HEADERS = {'app-key': os.environ['a3'], 'origin': os.environ['a4'], 'referer': os.environ['a4']} def login(loginId, password): try: data = {'loginId': loginId, 'password': password} cookies = {'720yun_v8_session': str(uuid.uuid4())} resp = requests.post(os.environ['a5'], data=data, headers=HEADERS, cookies=cookies) if resp.status_code == 200: return resp.json()['data']['token'] except Exception as e: LOGGER.error(e) raise gr.Error('登录错误,请确认你的720yun账号是否正确') def create_panorama(prompt, negative_prompt): try: data = { 'api_key': os.environ['a2'], 'generator': 'stable-skybox', 'prompt': prompt.strip()[0:598], 'negative_text': negative_prompt.strip()[0:398] } resp = requests.post(os.environ['a1'], data=data) LOGGER.info(resp.text) if resp.status_code == 200: time.sleep(15) request_id = resp.json()['request']['id'] flag = True countdown = 50 while flag: countdown -= 1 if countdown <= 0: raise gr.Error('AI老师罢工了,请稍后重试') resp = requests.get(f'{os.environ["a1"]}/{request_id}?api_key={os.environ["a2"]}') if resp.status_code == 200: progress_data = resp.json()['request'] if progress_data['progress'] == 100 and progress_data['status'] == 'complete': flag = False return request_id, progress_data['file_url'] time.sleep(1) except Exception as e: LOGGER.error(e) raise gr.Error('AI老师罢工了,请稍后重试') def upload(token, file_id, file_url): now = int(time.time()) data = [{ 'fileId': f'{file_id}-{now}', 'name': f'AI素材-{now}', 'watermarked': 0, 'size': 1024 * 1024 * 6, 'albumId': 0, 'exif': {}, 'gps': {}, 'panoId': 0, 'action': 1 }] HEADERS['app-authorization'] = token try: resp = requests.post(os.environ['a6'], data={'panos': json.dumps(data)}, headers=HEADERS) if resp.status_code == 200: resp_data = resp.json()['data'][0] access_key_id = resp_data['accessKeyId'] security_token = resp_data['securityToken'] accessKey_secret = resp_data['accessKeySecret'] bucket_name = resp_data['bucketName'] path = resp_data['path'][1:] endpoint = resp_data['endpointO'] pano_id = resp_data['panoId'] task_id = resp_data['taskId'] expired = resp_data['expired'] auth = oss2.StsAuth(access_key_id, accessKey_secret, security_token) bucket = oss2.Bucket(auth, endpoint, bucket_name) input_stream = requests.get(file_url) result = bucket.put_object(f'{path}/{pano_id}.jpg', input_stream) if result.status == 200: resp = requests.post(f'{os.environ["a6"]}/{task_id}', data={'status': 3, 'expired': expired}, headers=HEADERS) if resp.status_code == 200: time.sleep(5) flag = True while flag: pano_ids = [pano['id'] for pano in requests.get(os.environ["a7"], headers=HEADERS).json()['data']] if pano_id not in pano_ids: flag = False break time.sleep(0.5) data = { 'name': f'AI全景作品-{now}', 'materials': json.dumps([{ 'type': 1, 'id': pano_id }]), 'templateId': 2, 'publishPlatform': 1, 'keywords': 'AI全景', 'source': 99 } resp = requests.post(os.environ['a8'], data=data, headers=HEADERS) if resp.status_code == 200: return resp.json()['data']['tid'] except Exception as e: LOGGER.error(e) raise gr.Error('AI老师罢工了,请稍后重试') def main(loginId, password, prompt, negative_prompt, state, progress=gr.Progress()): try: if 'token' not in state: state['token'] = login(loginId, password) token = state['token'] file_id, image = create_panorama(prompt, negative_prompt) panorama_id = upload(token, file_id, image) return f'https://www.720yun.com/vr/{panorama_id}' except Exception as e: return f'{e}' with gr.Blocks(css=CSS) as demo: session = gr.State({}) gr.Markdown(""" # 创造属于你自己的AI全景 1. 需要你的 **[720yun.com](https://www.720yun.com)** 账号. 2. 由 **[720yun.com](https://www.720yun.com)** 提供支持. 3. 描述例子: a beautiful matte painting, northernmost continent, a gigantic square fortress covered by blizzard, epic composition, post apocalyptic, sci-fi, futuristic, fantasy, by Jan Urschel and Sergey Vasnev and Emmanuel Shiu and Michal Karcz, cinematic, cinematic lighting, light effect, epic, octane render, unreal engine """) with gr.Row(): with gr.Column(): login_id = gr.Textbox(label='账号: (必填)', placeholder='720yun 账号') with gr.Column(): password = gr.Textbox(label='密码: (必填)', type='password', placeholder='720yun 密码') with gr.Row(): prompt = gr.Textbox(label='描述: (必填)', lines=4, placeholder='请使用英文输入描述,最多600个字符') with gr.Row(): negative_prompt = gr.Textbox(label='负面描述', lines=2, placeholder='请使用英文输入负面描述,最多400个字符') with gr.Row(): out = gr.Textbox(label='输出') btn = gr.Button('运行') btn.click(fn=main, inputs=[login_id, password, prompt, negative_prompt, session], outputs=out, show_progress=True) demo.queue(concurrency_count=8).launch()