├── backend ├── __init__.py ├── ai │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-310.pyc │ │ ├── checktokens.cpython-310.pyc │ │ ├── get_response.cpython-310.pyc │ │ └── setaiconfig.cpython-310.pyc │ ├── checktokens.py │ ├── setaiconfig.py │ └── get_response.py ├── entities │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-310.pyc │ │ └── exceptions.cpython-310.pyc │ └── exceptions.py ├── route │ ├── __init__.py │ ├── __pycache__ │ │ ├── getfile.cpython-310.pyc │ │ ├── __init__.cpython-310.pyc │ │ ├── getanswer.cpython-310.pyc │ │ └── saveanswer.cpython-310.pyc │ ├── getanswer.py │ ├── getfile.py │ └── saveanswer.py ├── service │ ├── __init__.py │ ├── __pycache__ │ │ ├── methods.cpython-310.pyc │ │ ├── __init__.cpython-310.pyc │ │ └── handle_service.cpython-310.pyc │ ├── handle_service.py │ └── methods.py ├── .gitignore ├── app.py ├── db.py └── requirements.txt ├── assets ├── 1.png ├── 2.png ├── 3.png └── OIG.jpg ├── frontend ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── assets │ │ ├── OIG.jpg │ │ ├── common │ │ │ └── common.js │ │ ├── tian.png │ │ ├── ali_pay.jpg │ │ ├── genshin.gif │ │ └── wechat_pay.jpg │ ├── store │ │ └── store.js │ ├── components │ │ ├── ShowQuestions.vue │ │ ├── MainContent.vue │ │ ├── TianliGenshin.vue │ │ ├── DonateMe.vue │ │ ├── DetailPage.vue │ │ ├── LoadingTips.vue │ │ ├── ClickTips.vue │ │ ├── FooterChoices.vue │ │ ├── SearchOldData.vue │ │ ├── ShowOldData.vue │ │ ├── GetQuestions.vue │ │ ├── SaveAnswer.vue │ │ └── GetSummarize.vue │ ├── main.js │ ├── App.vue │ └── router │ │ └── index.js ├── babel.config.js ├── vue.config.js ├── .gitignore ├── jsconfig.json ├── README.md └── package.json ├── .vscode └── launch.json ├── Dockerfile └── README.md /backend/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/ai/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/entities/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/route/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/service/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | config.py 2 | 3 | /myvenv 4 | 5 | /sql.db -------------------------------------------------------------------------------- /assets/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/assets/1.png -------------------------------------------------------------------------------- /assets/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/assets/2.png -------------------------------------------------------------------------------- /assets/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/assets/3.png -------------------------------------------------------------------------------- /assets/OIG.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/assets/OIG.jpg -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/src/assets/OIG.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/frontend/src/assets/OIG.jpg -------------------------------------------------------------------------------- /frontend/src/assets/common/common.js: -------------------------------------------------------------------------------- 1 | const backend_prefix = '' 2 | export default{ 3 | backend_prefix 4 | } -------------------------------------------------------------------------------- /frontend/src/assets/tian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/frontend/src/assets/tian.png -------------------------------------------------------------------------------- /frontend/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/assets/ali_pay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/frontend/src/assets/ali_pay.jpg -------------------------------------------------------------------------------- /frontend/src/assets/genshin.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/frontend/src/assets/genshin.gif -------------------------------------------------------------------------------- /frontend/src/assets/wechat_pay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/frontend/src/assets/wechat_pay.jpg -------------------------------------------------------------------------------- /backend/ai/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/backend/ai/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /backend/route/__pycache__/getfile.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/backend/route/__pycache__/getfile.cpython-310.pyc -------------------------------------------------------------------------------- /frontend/src/store/store.js: -------------------------------------------------------------------------------- 1 | import {reactive} from 'vue' 2 | 3 | export const store = reactive({ 4 | content:'', 5 | currentContent:[], 6 | }) -------------------------------------------------------------------------------- /backend/ai/__pycache__/checktokens.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/backend/ai/__pycache__/checktokens.cpython-310.pyc -------------------------------------------------------------------------------- /backend/ai/__pycache__/get_response.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/backend/ai/__pycache__/get_response.cpython-310.pyc -------------------------------------------------------------------------------- /backend/ai/__pycache__/setaiconfig.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/backend/ai/__pycache__/setaiconfig.cpython-310.pyc -------------------------------------------------------------------------------- /backend/route/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/backend/route/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /backend/route/__pycache__/getanswer.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/backend/route/__pycache__/getanswer.cpython-310.pyc -------------------------------------------------------------------------------- /backend/service/__pycache__/methods.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/backend/service/__pycache__/methods.cpython-310.pyc -------------------------------------------------------------------------------- /frontend/vue.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('@vue/cli-service') 2 | module.exports = defineConfig({ 3 | transpileDependencies: true 4 | }) 5 | -------------------------------------------------------------------------------- /backend/entities/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/backend/entities/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /backend/route/__pycache__/saveanswer.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/backend/route/__pycache__/saveanswer.cpython-310.pyc -------------------------------------------------------------------------------- /backend/service/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/backend/service/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /backend/entities/__pycache__/exceptions.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/backend/entities/__pycache__/exceptions.cpython-310.pyc -------------------------------------------------------------------------------- /backend/service/__pycache__/handle_service.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangcham/ppt_killer/HEAD/backend/service/__pycache__/handle_service.cpython-310.pyc -------------------------------------------------------------------------------- /frontend/src/components/ShowQuestions.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /backend/entities/exceptions.py: -------------------------------------------------------------------------------- 1 | class EmptyFileError(Exception): 2 | pass 3 | 4 | class ImageTransferError(Exception): 5 | pass 6 | 7 | class GetContentError(Exception): 8 | pass 9 | 10 | class ChatgptGenerateError(Exception): 11 | pass 12 | 13 | class SqliteError(Exception): 14 | pass -------------------------------------------------------------------------------- /frontend/src/components/MainContent.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /frontend/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "baseUrl": "./", 6 | "moduleResolution": "node", 7 | "paths": { 8 | "@/*": [ 9 | "src/*" 10 | ] 11 | }, 12 | "lib": [ 13 | "esnext", 14 | "dom", 15 | "dom.iterable", 16 | "scripthost" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/components/TianliGenshin.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | 19 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # frontend 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | npm run lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /backend/ai/checktokens.py: -------------------------------------------------------------------------------- 1 | import tiktoken 2 | 3 | class CheckTokens: 4 | def get_num_tokens(self,text) -> int: 5 | encoding = tiktoken.get_encoding("cl100k_base") 6 | encoding = tiktoken.encoding_for_model("gpt-3.5-turbo") 7 | 8 | num_tokens = len(encoding.encode(text)) 9 | print(num_tokens) 10 | if num_tokens >= 3500: 11 | return 1 12 | else: 13 | return 2 14 | 15 | -------------------------------------------------------------------------------- /backend/ai/setaiconfig.py: -------------------------------------------------------------------------------- 1 | import openai 2 | import os 3 | 4 | def setconfig(): 5 | 6 | # openai.proxy = "http://127.0.0.1:7890" 7 | # openai.api_key = config.openai_api_key 8 | 9 | 10 | 11 | if os.getenv('API_BASE') == '': 12 | openai.api_key = os.environ.get('API_KEY',"None") 13 | print("环境变量"+openai.api_key) 14 | else: 15 | openai.api_key = os.getenv('API_KEY') 16 | openai.api_base = os.getenv('API_BASE') -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "chrome", 9 | "request": "launch", 10 | "name": "针对 localhost 启动 Chrome", 11 | "url": "http://localhost:8080", 12 | "webRoot": "${workspaceFolder}" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /frontend/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | import ElementPlus from 'element-plus' 4 | import 'element-plus/dist/index.css' 5 | import * as ElementPlusIconsVue from '@element-plus/icons-vue' 6 | import router from './router/index' 7 | 8 | const app = createApp(App) 9 | app.use(ElementPlus) 10 | for (const [key, component] of Object.entries(ElementPlusIconsVue)) { 11 | app.component(key, component) 12 | } 13 | app.use(router) 14 | app.mount('#app') 15 | 16 | -------------------------------------------------------------------------------- /frontend/src/App.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 22 | 23 | > 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | 3 | RUN apt-get update -y 4 | 5 | RUN apt-get install -y python3.9 python3-pip 6 | 7 | RUN apt-get install -y tesseract-ocr 8 | 9 | RUN apt-get install -y wget 10 | RUN wget https://github.com/tesseract-ocr/tessdata_best/blob/main/chi_sim.traineddata 11 | RUN mv chi_sim.traineddata /usr/share/tesseract-ocr/4.00/tessdata/ 12 | 13 | WORKDIR /app 14 | 15 | COPY backend ./backend 16 | COPY frontend/dist ./frontend/dist 17 | 18 | RUN pip3 install -r backend/requirements.txt 19 | 20 | EXPOSE 5000 21 | 22 | ENV API_KEY="" 23 | ENV API_BASE="" 24 | 25 | CMD [ "python3","backend/app.py" ] -------------------------------------------------------------------------------- /frontend/src/components/DonateMe.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | 17 | -------------------------------------------------------------------------------- /frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /frontend/src/components/DetailPage.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 30 | 31 | -------------------------------------------------------------------------------- /frontend/src/router/index.js: -------------------------------------------------------------------------------- 1 | import {createRouter,createWebHistory} from 'vue-router' 2 | import GetSummarize from '../components/GetSummarize.vue' 3 | import SearchOldData from '../components/SearchOldData.vue' 4 | import DetailPage from '../components/DetailPage.vue' 5 | import ShowOldData from '../components/ShowOldData.vue' 6 | const routes = [ 7 | { path :'/',redirect:'/GetSummarize'}, 8 | { path :'/GetSummarize',name:'/GetSummarize',components:{GetSummarize:GetSummarize}}, 9 | { path : '/SearchOldData',name:'/SearchOldData',components:{SearchOldData:SearchOldData}}, 10 | { path : '/DetailPage',name:'/DetailPage',components:{DetailPage:DetailPage}}, 11 | { path:'/ShowOldData',name:'/ShowOldData',components:{ShowOldData:ShowOldData}}, 12 | ] 13 | 14 | const router = createRouter({ 15 | history: createWebHistory(), 16 | routes 17 | }); 18 | 19 | export default router -------------------------------------------------------------------------------- /frontend/src/components/LoadingTips.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 25 | 26 | -------------------------------------------------------------------------------- /backend/app.py: -------------------------------------------------------------------------------- 1 | from quart import send_from_directory, render_template 2 | from quart import Quart, request, Blueprint 3 | from route.getfile import getfile_app 4 | from route.getanswer import getanswer_app 5 | from route.saveanswer import saveanswer_app 6 | import os 7 | import asyncio 8 | import db 9 | 10 | app = Quart(__name__, template_folder="../frontend/dist", static_folder="../frontend/dist", static_url_path="") 11 | 12 | app.register_blueprint(getfile_app) 13 | app.register_blueprint(getanswer_app) 14 | app.register_blueprint(saveanswer_app) 15 | 16 | @app.route('/') 17 | async def index(): 18 | return await render_template("index.html") 19 | 20 | if __name__ == '__main__': 21 | loop = asyncio.get_event_loop() 22 | try: 23 | database = db.database() 24 | database.create() 25 | loop.run_until_complete(app.run_task(host='0.0.0.0', port=5000)) 26 | except KeyboardInterrupt: 27 | pass 28 | finally: 29 | loop.close() -------------------------------------------------------------------------------- /backend/route/getanswer.py: -------------------------------------------------------------------------------- 1 | from quart import Blueprint,request,jsonify,Quart 2 | from quart_cors import cors 3 | import db 4 | from entities.exceptions import SqliteError 5 | 6 | getanswer_app = Blueprint('getanswer_app',__name__) 7 | cors(getanswer_app) 8 | @getanswer_app.route('/olddata',methods=['post']) 9 | async def olddata(): 10 | data = await request.get_json() 11 | token = data['content'] 12 | try: 13 | database = db.database() 14 | sql = "select type,content from info where token = ?" 15 | results = database.execute(sql,(token,)) 16 | 17 | if not results: 18 | return jsonify({'status':'fail','message':'未查询到符合该密钥的结果'}) 19 | else: 20 | data = [] 21 | for result in results: 22 | type = result[0] 23 | content = result[1] 24 | 25 | item = {'type':type,'content':content} 26 | data.append(item) 27 | 28 | return jsonify(data) 29 | except SqliteError: 30 | return jsonify({'status':'fail','message':'数据库操作失败'}) -------------------------------------------------------------------------------- /backend/db.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | #create table 3 | table_one = """ 4 | CREATE TABLE if not exists info( 5 | token VARCHAR(255), 6 | type INT, 7 | content TEXT 8 | ) 9 | """ 10 | 11 | 12 | class database: 13 | def execute(self,query,args=None): 14 | self.conn = None 15 | self.cursor = None 16 | try: 17 | self.conn = sqlite3.connect('sql.db') 18 | self.cursor = self.conn.cursor() 19 | 20 | if args: 21 | self.cursor.execute(query,args) 22 | else: 23 | self.cursor.execute(query) 24 | 25 | results = self.cursor.fetchall() 26 | self.conn.commit() 27 | 28 | return results 29 | 30 | except Exception as e: 31 | print(e) 32 | if self.conn: 33 | self.conn.rollback() 34 | 35 | 36 | def close(self): 37 | if self.conn: 38 | self.conn.close() 39 | 40 | def create(self): 41 | self.execute(table_one) 42 | print("成功建表") 43 | 44 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "@element-plus/icons-vue": "^2.1.0", 12 | "axios": "^1.5.1", 13 | "core-js": "^3.8.3", 14 | "element-plus": "^2.4.0", 15 | "libgif": "^0.0.3", 16 | "markdown-it": "^13.0.2", 17 | "vue": "^3.2.13", 18 | "vue-router": "^4.2.5" 19 | }, 20 | "devDependencies": { 21 | "@babel/core": "^7.12.16", 22 | "@babel/eslint-parser": "^7.12.16", 23 | "@types/markdown-it": "^13.0.2", 24 | "@vue/cli-plugin-babel": "~5.0.0", 25 | "@vue/cli-plugin-eslint": "~5.0.0", 26 | "@vue/cli-service": "~5.0.0", 27 | "eslint": "^7.32.0", 28 | "eslint-plugin-vue": "^8.0.3" 29 | }, 30 | "eslintConfig": { 31 | "root": true, 32 | "env": { 33 | "node": true 34 | }, 35 | "extends": [ 36 | "plugin:vue/vue3-essential", 37 | "eslint:recommended" 38 | ], 39 | "parserOptions": { 40 | "parser": "@babel/eslint-parser" 41 | }, 42 | "rules": {} 43 | }, 44 | "browserslist": [ 45 | "> 1%", 46 | "last 2 versions", 47 | "not dead", 48 | "not ie 11" 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /backend/service/handle_service.py: -------------------------------------------------------------------------------- 1 | import os 2 | from typing import IO 3 | from . import methods 4 | from quart import jsonify 5 | 6 | ALLOWED_EXTENSIONS = {'ppt','pptx'} 7 | 8 | def allowed_file(filename): 9 | return '.' in filename and \ 10 | filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS 11 | 12 | 13 | class handle_file: 14 | def __init__(self,file:IO): 15 | self.file = file 16 | 17 | async def checkext(self): 18 | #在这里检查文件格式 19 | if not allowed_file(self.file.filename): 20 | return jsonify({'status':'fail','message':'不是允许的文件类型'}) 21 | 22 | ext = os.path.splitext(self.file.filename)[1] 23 | print('接受到的文件拓展名:'+ext) 24 | self.ext = ext 25 | 26 | async def handle(self): 27 | if self.file: 28 | print("文件存在") 29 | 30 | method = methods.GetText(self.file) 31 | 32 | if(self.ext == '.pptx'): 33 | print("进入pptx文件使用") 34 | result =await method.pptx_method() 35 | elif(self.ext == '.ppt'): 36 | result =await method.ppt_method() 37 | 38 | return result 39 | 40 | 41 | @classmethod 42 | async def create(cls,file:IO): 43 | instance = cls(file) 44 | await instance.checkext() 45 | return instance 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /backend/route/getfile.py: -------------------------------------------------------------------------------- 1 | import traceback 2 | from quart import request,Blueprint,jsonify 3 | from quart_cors import cors 4 | import service.handle_service as hs 5 | from entities.exceptions import GetContentError,EmptyFileError 6 | import ai.get_response as gr 7 | 8 | 9 | getfile_app = Blueprint('getfile_app',__name__) 10 | cors(getfile_app) 11 | 12 | @getfile_app.route('/getfile',methods=['post']) 13 | async def getfile(): 14 | try: 15 | files = await request.files 16 | file = files.get('file', None) 17 | 18 | if file: 19 | print('后端接受到文件') 20 | file_handler =await hs.handle_file.create(file) 21 | response = await file_handler.handle() 22 | print("进行操作,得到ppt") 23 | return response 24 | else: 25 | return jsonify({'status':'fail','message':'接受文件失败','code':'0'}) 26 | except EmptyFileError: 27 | print(traceback.format_exc()) 28 | return jsonify({'status':'fail','message':'抛出异常'}) 29 | 30 | @getfile_app.route('/getques',methods=['post']) 31 | async def getques(): 32 | try: 33 | data = await request.get_json() 34 | content = data['content'] 35 | #编写逻辑 36 | if content: 37 | getres = gr.response(content) 38 | result = await getres.get_generated_answer(content) 39 | 40 | return result 41 | else: 42 | return jsonify({'status':'fail','message':'获得的内容为空'}) 43 | 44 | except GetContentError as e: 45 | return jsonify({'status':'fail','message':'获得内容失败'}) 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /backend/route/saveanswer.py: -------------------------------------------------------------------------------- 1 | from quart import Quart,request,jsonify,Blueprint 2 | from quart_cors import cors 3 | import db 4 | from entities.exceptions import SqliteError 5 | saveanswer_app = Blueprint('saveanswer_app',__name__) 6 | 7 | cors(saveanswer_app) 8 | 9 | @saveanswer_app.route('/saveanswer',methods=['post']) 10 | async def saveanswer(): 11 | data = await request.get_json() 12 | content = data['content'] 13 | type = data['type'] 14 | token = data['token'] 15 | 16 | sql1 = "select * from info where token = ?" 17 | database = db.database() 18 | result = database.execute(sql1,(token,)) 19 | if not result: 20 | return jsonify({'code':'1'}) 21 | else: 22 | sql2 = "INSERT INTO info (token,type,content) VALUES (?,?,?)" 23 | try: 24 | result = database.execute(sql2,(token,type,content,)) 25 | return jsonify({'status':'success','code':'3'}) 26 | except SqliteError: 27 | print("数据库插入操作失败") 28 | return jsonify({'status':'fail','message':'数据库插入操作失败','code':'2'}) 29 | 30 | @saveanswer_app.route('/saveagain',methods=['post']) 31 | async def saveagain(): 32 | data = await request.get_json() 33 | content = data['content'] 34 | type = data['type'] 35 | token = data['token'] 36 | 37 | sql2 = "INSERT INTO info (token,type,content) VALUES (?,?,?)" 38 | try: 39 | database = db.database() 40 | database.execute(sql2,(token,type,content,)) 41 | return jsonify({'status':'success','message':'保存成功'}) 42 | except SqliteError: 43 | return jsonify({'status':'fail','message':'数据库操作失败'}) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | # PPT-killer 6 | 7 | 点击使用[公共体验服务](https://www.pptkiller.top) 8 | 9 | ## 功能 10 | 11 | 1. 支持将pptx文件投喂给chatgpt,总结pptx的内容 12 | 2. 支持根据AI的总结生成与pptx文件相关的问题 13 | 3. 支持docker部署并填写自己的API_key和API_base 14 | 4. 可选择是否保存AI生成的总结与问题 15 | 16 | ## 部署 17 | 18 | ### 基于docker部署(推荐) 19 | 20 | #### 配置项: 21 | 22 | API_KEY : 对应自己的api key(必填)
23 | API_BASE : 对应自己的base url(可填可不填) 24 | 25 | ``` 26 | #拉取docker镜像 27 | docker pull wangcham/pptkiller 28 | 29 | #启动!(可加入环境变量API_BASE,本条命令没有加) 30 | docker run -it -d -p 5000:5000 -e API_KEY=your-api-key --name pptkiller wangcham/pptkiller 31 | ``` 32 | 33 | ### 手动部署 34 | 35 | ``` 36 | #拉取源代码(国内用户可使用gitee地址拉取代码) 37 | git clone https://github.com/wangcham/ppt_killer.git 38 | 39 | #进入前端 40 | cd ppt_killer/frontend 41 | 42 | npm install 43 | 44 | npm run build 45 | 46 | #进入后端 47 | cd ppt_killer/backend 48 | pip install -r requirements.txt 49 | python3 app.py 50 | ``` 51 | 52 | 强烈推荐使用docker部署! 53 | 54 | 安装好之后,在浏览器打开IP地址:5000就可以看到部署成功的pptkiller 55 | 56 | 57 | ### 建议配合free-one-api与one-api食用 58 | 59 | 这两个仓库是管理api key的,其中free-one-api为逆向库。
60 | 查看 [free-one-api](https://github.com/RockChinQ/free-one-api)
61 | 查看 [one-api](https://github.com/songquanpeng/one-api/)
62 | 目前one-api使用可能出现报错http code 200的问题,谨慎使用!(可能是使用的openai库版本较低的原因,后续会修复以配合one-api) 63 | 64 | 65 | 66 | ## 网站截图 67 | 68 |
69 | 70 |
71 | 72 | 73 | ## 后续会支持的功能 74 | 1. 支持将文本切分成小段,以加快响应速度 75 | 2. 可供用户选择的其他模型与配置 76 | 3. 页面优化 77 | 78 | ## 特别感谢 79 | @[theLazy](https://thelazy.cn/)设计的天理原神启动页动画,素材在[此仓库](https://github.com/the-lazy-me/sourceBox)中 80 | -------------------------------------------------------------------------------- /frontend/src/components/ClickTips.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 43 | 44 | -------------------------------------------------------------------------------- /frontend/src/components/FooterChoices.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 52 | 53 | -------------------------------------------------------------------------------- /frontend/src/components/SearchOldData.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 55 | 56 | -------------------------------------------------------------------------------- /backend/service/methods.py: -------------------------------------------------------------------------------- 1 | import io 2 | import traceback 3 | from typing import IO 4 | from pptx import Presentation 5 | from pptx.util import Inches,Pt 6 | import pytesseract 7 | from PIL import Image 8 | import ai.get_response 9 | 10 | 11 | 12 | class GetText: 13 | def __init__(self,file:IO): 14 | self.file = file 15 | 16 | 17 | async def pptx_method(self): 18 | text = "" 19 | presentation = Presentation(self.file) 20 | print("pptxmethod内部") 21 | try: 22 | for slide in presentation.slides: 23 | for shape in slide.shapes: 24 | if hasattr(shape, 'text'): 25 | text += shape.text + '\n' 26 | if shape.shape_type == 13: 27 | image = shape.image 28 | try: 29 | img = Image.open(io.BytesIO(image.blob)) 30 | img = img.convert('L') 31 | img_text = pytesseract.image_to_string(img) 32 | text += img_text + '\n' 33 | except Exception as e: 34 | print("有图片异常") 35 | # 检查是否有text 36 | if not text: 37 | print("no text") 38 | 39 | self.text = text 40 | #存数据库 41 | print("pptx发送ai") 42 | result = await self.send_to_ai(self.text) 43 | return result 44 | 45 | except Exception as e: 46 | print("读取文件内容异常") 47 | print(traceback.format_exc()) 48 | return "读取文件异常" 49 | 50 | async def ppt_method(self): 51 | print("ppt file") 52 | return "无法解析ppt文件,正在加紧开发,请尝试使用其他网站转换文件格式或者使用PowerPoint将ppt文件改成pptx文件再使用" 53 | 54 | async def send_to_ai(self,alltext): 55 | print("send to ai") 56 | operate =ai.get_response.response(alltext) 57 | result = await operate.complete() 58 | return result 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /backend/ai/get_response.py: -------------------------------------------------------------------------------- 1 | from . import checktokens 2 | import os 3 | import traceback 4 | import openai 5 | from quart import jsonify 6 | from entities.exceptions import ChatgptGenerateError 7 | from . import setaiconfig 8 | class response: 9 | def __init__(self, text): 10 | self.text = text 11 | 12 | async def complete(self): 13 | try: 14 | 15 | setaiconfig.setconfig() 16 | 17 | check = checktokens.CheckTokens() 18 | type = check.get_num_tokens(self.text) 19 | if type == 1: 20 | used_model = "gpt-3.5-turbo-16k" 21 | print("调用gpt16k") 22 | if type == 2: 23 | used_model = "gpt-3.5-turbo" 24 | print("调用gpt3.5turbo接口") 25 | 26 | completion = openai.ChatCompletion.create( 27 | model=used_model, 28 | messages=[ 29 | {"role": "system", "content": "你是一个帮助人们总结内容的助手"}, 30 | {"role": "user", "content": "请给我总结这些内容,我给你的文本的内容是乱的,请你认真思考一下,把他整理清楚,给出我中文的回复,不允许省略回复,以分层标题等的形式生成大纲,另外,生成的回答必须是markdown格式,记得写成垂直方向的换行,也就是需要你加换行的标志,让他形式好看一点,并且请翻译成中文:" + self.text} 31 | ] 32 | ) 33 | self.result = completion.choices[0].message['content'] 34 | print(self.result) 35 | return jsonify({'status':'success','result':self.result}) 36 | except Exception as e: 37 | print(traceback.format_exc()) 38 | self.result = "#### chatgpt响应异常,异常是" + str(e) + "请稍后使用网站~" 39 | return jsonify({'status':'fail','result':self.result}) 40 | 41 | async def get_generated_answer(self,ques_text): 42 | 43 | setaiconfig.setconfig() 44 | 45 | check = checktokens.CheckTokens() 46 | type = check.get_num_tokens(ques_text) 47 | 48 | if type == 1: 49 | used_model = "gpt-3.5-turbo-16k" 50 | if type == 2: 51 | used_model = "gpt-3.5-turbo" 52 | 53 | try: 54 | completion = openai.ChatCompletion.create( 55 | model=used_model, 56 | messages=[ 57 | {"role": "system", "content": "你是一个帮助人们理解PPT的助手"}, 58 | {"role": "user", "content": "请将这些杂乱的文本整理清楚,然后依据这些内容生成大约二三十道问题,并且在最后给出答案,然后必须以markdown的形式发送给我,文本内容是:" + ques_text} 59 | ] 60 | ) 61 | result = completion.choices[0].message['content'] 62 | return jsonify({'status':'success','result':result}) 63 | except ChatgptGenerateError: 64 | return jsonify({'status':'fail','message':'chatgpt生成内容失败'}) -------------------------------------------------------------------------------- /backend/requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.10 3 | # by the following command: 4 | # 5 | # pip-compile requirements.in 6 | # 7 | --index-url https://pypi.tuna.tsinghua.edu.cn/simple 8 | 9 | aiofiles==23.2.1 10 | # via quart 11 | annotated-types==0.6.0 12 | # via pydantic 13 | anyio==3.7.1 14 | # via 15 | # httpx 16 | # openai 17 | blinker==1.7.0 18 | # via 19 | # flask 20 | # quart 21 | certifi==2023.7.22 22 | # via 23 | # httpcore 24 | # httpx 25 | # requests 26 | charset-normalizer==3.3.2 27 | # via requests 28 | click==8.1.7 29 | # via 30 | # flask 31 | # quart 32 | colorama==0.4.6 33 | # via 34 | # click 35 | # tqdm 36 | distro==1.8.0 37 | # via openai 38 | exceptiongroup==1.1.3 39 | # via 40 | # anyio 41 | # taskgroup 42 | flask==3.0.0 43 | # via quart 44 | h11==0.14.0 45 | # via 46 | # httpcore 47 | # hypercorn 48 | # wsproto 49 | h2==4.1.0 50 | # via hypercorn 51 | hpack==4.0.0 52 | # via h2 53 | httpcore==1.0.1 54 | # via httpx 55 | httpx==0.25.1 56 | # via openai 57 | hypercorn==0.15.0 58 | # via quart 59 | hyperframe==6.0.1 60 | # via h2 61 | idna==3.4 62 | # via 63 | # anyio 64 | # httpx 65 | # requests 66 | itsdangerous==2.1.2 67 | # via 68 | # flask 69 | # quart 70 | jinja2==3.1.2 71 | # via 72 | # flask 73 | # quart 74 | lxml==4.9.3 75 | # via python-pptx 76 | markupsafe==2.1.3 77 | # via 78 | # jinja2 79 | # quart 80 | # werkzeug 81 | openai==0.28 82 | # via -r requirements.in 83 | packaging==23.2 84 | # via pytesseract 85 | pillow==10.1.0 86 | # via 87 | # -r requirements.in 88 | # pytesseract 89 | # python-pptx 90 | priority==2.0.0 91 | # via hypercorn 92 | pydantic==2.4.2 93 | # via openai 94 | pydantic-core==2.10.1 95 | # via pydantic 96 | pytesseract==0.3.10 97 | # via -r requirements.in 98 | python-pptx==0.6.23 99 | # via -r requirements.in 100 | quart==0.19.3 101 | # via 102 | # -r requirements.in 103 | # quart-cors 104 | quart-cors==0.7.0 105 | # via -r requirements.in 106 | regex==2023.10.3 107 | # via tiktoken 108 | requests==2.31.0 109 | # via tiktoken 110 | sniffio==1.3.0 111 | # via 112 | # anyio 113 | # httpx 114 | taskgroup==0.0.0a4 115 | # via hypercorn 116 | tiktoken==0.5.1 117 | # via -r requirements.in 118 | tomli==2.0.1 119 | # via hypercorn 120 | tqdm==4.66.1 121 | # via openai 122 | typing-extensions==4.8.0 123 | # via 124 | # openai 125 | # pydantic 126 | # pydantic-core 127 | urllib3==2.0.7 128 | # via requests 129 | werkzeug==3.0.1 130 | # via 131 | # flask 132 | # quart 133 | wsproto==1.2.0 134 | # via hypercorn 135 | xlsxwriter==3.1.9 136 | # via python-pptx 137 | -------------------------------------------------------------------------------- /frontend/src/components/ShowOldData.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 60 | 61 | -------------------------------------------------------------------------------- /frontend/src/components/GetQuestions.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 116 | 117 | -------------------------------------------------------------------------------- /frontend/src/components/SaveAnswer.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 115 | 116 | -------------------------------------------------------------------------------- /frontend/src/components/GetSummarize.vue: -------------------------------------------------------------------------------- 1 | 72 | 73 | 212 | 213 | --------------------------------------------------------------------------------