99i commited on
Commit
f9a40b7
·
verified ·
1 Parent(s): 8eccaf7

Upload 3 files

Browse files
Files changed (3) hide show
  1. Dockerfile +32 -0
  2. main.py +206 -0
  3. requirements.txt +6 -0
Dockerfile ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 使用官方Python运行时作为基础镜像
2
+ FROM python:3.12-slim
3
+
4
+ # 设置工作目录
5
+ WORKDIR /app
6
+
7
+ # 设置环境变量
8
+ ENV PYTHONDONTWRITEBYTECODE=1 \
9
+ PYTHONUNBUFFERED=1
10
+
11
+ # 安装系统依赖
12
+ RUN apt-get update && apt-get install -y \
13
+ gcc \
14
+ && rm -rf /var/lib/apt/lists/*
15
+
16
+ # 复制requirements文件
17
+ COPY requirements.txt .
18
+
19
+ # 安装Python依赖
20
+ RUN pip install --no-cache-dir -r requirements.txt
21
+
22
+ # 复制应用代码
23
+ COPY . .
24
+
25
+ # 创建static目录并设置权限
26
+ RUN mkdir -p static && chmod 755 static
27
+
28
+ # 暴露端口
29
+ EXPOSE 8000
30
+
31
+ # 运行应用
32
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
main.py ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from fastapi.staticfiles import StaticFiles
3
+ from fastapi.responses import HTMLResponse
4
+ from pydantic import BaseModel
5
+ import markdown
6
+ import aiofiles
7
+ import os
8
+ import uuid
9
+ from datetime import datetime
10
+ import json
11
+
12
+ app = FastAPI(title="HTML/Markdown Preview API", version="1.0.0")
13
+
14
+ # 挂载静态文件目录
15
+ app.mount("/static", StaticFiles(directory="static"), name="static")
16
+
17
+ class HTMLRequest(BaseModel):
18
+ html_content: str
19
+
20
+ class MarkdownRequest(BaseModel):
21
+ markdown_content: str
22
+
23
+ class PreviewResponse(BaseModel):
24
+ url: str
25
+ message: str
26
+
27
+ def generate_filename(extension: str = ".html") -> str:
28
+ """生成唯一的文件名"""
29
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
30
+ unique_id = str(uuid.uuid4())[:8]
31
+ return f"{timestamp}_{unique_id}{extension}"
32
+
33
+ async def save_html_file(content: str, filename: str) -> str:
34
+ """保存HTML内容到文件"""
35
+ file_path = os.path.join("static", filename)
36
+ async with aiofiles.open(file_path, 'w', encoding='utf-8') as f:
37
+ await f.write(content)
38
+ return filename
39
+
40
+ def markdown_to_html(markdown_content: str) -> str:
41
+ """将Markdown转换为HTML"""
42
+ # 配置markdown扩展
43
+ extensions = [
44
+ 'markdown.extensions.extra',
45
+ 'markdown.extensions.codehilite',
46
+ 'markdown.extensions.toc',
47
+ 'markdown.extensions.tables',
48
+ 'markdown.extensions.fenced_code'
49
+ ]
50
+
51
+ # 转换markdown为HTML
52
+ html_content = markdown.markdown(markdown_content, extensions=extensions)
53
+
54
+ # 包装在完整的HTML文档中
55
+ full_html = f"""
56
+ <!DOCTYPE html>
57
+ <html lang="zh-CN">
58
+ <head>
59
+ <meta charset="UTF-8">
60
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
61
+ <title>Markdown Preview</title>
62
+ <style>
63
+ body {{
64
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
65
+ line-height: 1.6;
66
+ max-width: 800px;
67
+ margin: 0 auto;
68
+ padding: 20px;
69
+ color: #333;
70
+ }}
71
+ h1, h2, h3, h4, h5, h6 {{
72
+ margin-top: 1.5em;
73
+ margin-bottom: 0.5em;
74
+ }}
75
+ code {{
76
+ background-color: #f4f4f4;
77
+ padding: 2px 4px;
78
+ border-radius: 3px;
79
+ font-family: 'Consolas', 'Monaco', monospace;
80
+ }}
81
+ pre {{
82
+ background-color: #f4f4f4;
83
+ padding: 10px;
84
+ border-radius: 5px;
85
+ overflow-x: auto;
86
+ }}
87
+ pre code {{
88
+ background-color: transparent;
89
+ padding: 0;
90
+ }}
91
+ blockquote {{
92
+ border-left: 4px solid #ddd;
93
+ margin: 0;
94
+ padding-left: 20px;
95
+ color: #666;
96
+ }}
97
+ table {{
98
+ border-collapse: collapse;
99
+ width: 100%;
100
+ margin: 1em 0;
101
+ }}
102
+ th, td {{
103
+ border: 1px solid #ddd;
104
+ padding: 8px;
105
+ text-align: left;
106
+ }}
107
+ th {{
108
+ background-color: #f2f2f2;
109
+ }}
110
+ img {{
111
+ max-width: 100%;
112
+ height: auto;
113
+ }}
114
+ </style>
115
+ </head>
116
+ <body>
117
+ {html_content}
118
+ </body>
119
+ </html>
120
+ """
121
+ return full_html
122
+
123
+ @app.post("/api/html/preview", response_model=PreviewResponse)
124
+ async def preview_html(request: HTMLRequest):
125
+ """
126
+ 接收HTML代码,返回在线访问链接
127
+ """
128
+ try:
129
+ # 生成唯一文件名
130
+ filename = generate_filename(".html")
131
+
132
+ # 保存HTML文件
133
+ await save_html_file(request.html_content, filename)
134
+
135
+ # 构建访问URL
136
+ url = f"http://localhost:8000/static/{filename}"
137
+
138
+ return PreviewResponse(
139
+ url=url,
140
+ message=f"HTML预览已创建,可通过链接访问"
141
+ )
142
+
143
+ except Exception as e:
144
+ raise HTTPException(status_code=500, detail=f"创建HTML预览失败: {str(e)}")
145
+
146
+ @app.post("/api/markdown/preview", response_model=PreviewResponse)
147
+ async def preview_markdown(request: MarkdownRequest):
148
+ """
149
+ 接收Markdown代码,返回渲染后的HTML在线访问链接
150
+ """
151
+ try:
152
+ # 将Markdown转换为HTML
153
+ html_content = markdown_to_html(request.markdown_content)
154
+
155
+ # 生成唯一文件名
156
+ filename = generate_filename(".html")
157
+
158
+ # 保存HTML文件
159
+ await save_html_file(html_content, filename)
160
+
161
+ # 构建访问URL
162
+ url = f"http://localhost:8000/static/{filename}"
163
+
164
+ return PreviewResponse(
165
+ url=url,
166
+ message=f"Markdown预览已创建,可通过链接访问"
167
+ )
168
+
169
+ except Exception as e:
170
+ raise HTTPException(status_code=500, detail=f"创建Markdown预览失败: {str(e)}")
171
+
172
+ @app.get("/")
173
+ async def root():
174
+ """
175
+ API根路径,返回使用说明
176
+ """
177
+ return {
178
+ "message": "HTML/Markdown Preview API",
179
+ "version": "1.0.0",
180
+ "endpoints": {
181
+ "html_preview": {
182
+ "url": "/api/html/preview",
183
+ "method": "POST",
184
+ "description": "接收HTML代码,返回在线访问链接",
185
+ "request_body": {
186
+ "html_content": "string - HTML代码内容"
187
+ }
188
+ },
189
+ "markdown_preview": {
190
+ "url": "/api/markdown/preview",
191
+ "method": "POST",
192
+ "description": "接收Markdown代码,返回渲染后的HTML在线访问链接",
193
+ "request_body": {
194
+ "markdown_content": "string - Markdown代码内容"
195
+ }
196
+ }
197
+ },
198
+ "example_usage": {
199
+ "html": "curl -X POST http://localhost:8000/api/html/preview -H 'Content-Type: application/json' -d '{\"html_content\": \"<h1>Hello World</h1>\"}'",
200
+ "markdown": "curl -X POST http://localhost:8000/api/markdown/preview -H 'Content-Type: application/json' -d '{\"markdown_content\": \"# Hello World\"}'"
201
+ }
202
+ }
203
+
204
+ if __name__ == "__main__":
205
+ import uvicorn
206
+ uvicorn.run(app, host="0.0.0.0", port=8000)
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ fastapi==0.104.1
2
+ uvicorn==0.24.0
3
+ python-multipart==0.0.6
4
+ markdown==3.5.1
5
+ jinja2==3.1.2
6
+ aiofiles==23.2.1