From 90f3103de3ac418525852f065a9d46488a0c895e Mon Sep 17 00:00:00 2001 From: rjb <263303411@qq.com> Date: Sun, 1 Mar 2026 23:24:53 +0800 Subject: [PATCH] a --- docs/api_expert_generate_3_open.md | 108 +++++++++++ exampleAiApp01/README.md | 29 +++ exampleAiApp01/app/build.gradle.kts | 46 +++++ exampleAiApp01/app/proguard-rules.pro | 3 + .../app/src/main/AndroidManifest.xml | 23 +++ .../example/promptoptimizer/MainActivity.java | 146 +++++++++++++++ .../promptoptimizer/RetrofitClient.java | 46 +++++ .../api/ExpertGenerate3Api.java | 17 ++ .../model/ExpertGenerate3Request.java | 71 +++++++ .../model/ExpertGenerate3Response.java | 120 ++++++++++++ .../app/src/main/res/drawable/edit_bg.xml | 6 + .../res/drawable/ic_launcher_foreground.xml | 10 + .../app/src/main/res/layout/activity_main.xml | 153 +++++++++++++++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../app/src/main/res/values/colors.xml | 5 + .../app/src/main/res/values/strings.xml | 14 ++ .../app/src/main/res/values/themes.xml | 8 + exampleAiApp01/build.gradle.kts | 3 + exampleAiApp01/gradle.properties | 4 + .../gradle/wrapper/gradle-wrapper.properties | 7 + exampleAiApp01/settings.gradle.kts | 17 ++ logs/app.log | 1 + logs/gunicorn.pid | 2 +- logs/gunicorn_access.log | 3 + logs/gunicorn_error.log | 33 ++++ .../expert_generate_3.cpython-312.pyc | Bin 11032 -> 11597 bytes .../routes/expert_generate_3.py | 174 ++++++++++-------- 28 files changed, 985 insertions(+), 74 deletions(-) create mode 100644 docs/api_expert_generate_3_open.md create mode 100644 exampleAiApp01/README.md create mode 100644 exampleAiApp01/app/build.gradle.kts create mode 100644 exampleAiApp01/app/proguard-rules.pro create mode 100644 exampleAiApp01/app/src/main/AndroidManifest.xml create mode 100644 exampleAiApp01/app/src/main/java/com/example/promptoptimizer/MainActivity.java create mode 100644 exampleAiApp01/app/src/main/java/com/example/promptoptimizer/RetrofitClient.java create mode 100644 exampleAiApp01/app/src/main/java/com/example/promptoptimizer/api/ExpertGenerate3Api.java create mode 100644 exampleAiApp01/app/src/main/java/com/example/promptoptimizer/model/ExpertGenerate3Request.java create mode 100644 exampleAiApp01/app/src/main/java/com/example/promptoptimizer/model/ExpertGenerate3Response.java create mode 100644 exampleAiApp01/app/src/main/res/drawable/edit_bg.xml create mode 100644 exampleAiApp01/app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 exampleAiApp01/app/src/main/res/layout/activity_main.xml create mode 100644 exampleAiApp01/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 exampleAiApp01/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 exampleAiApp01/app/src/main/res/values/colors.xml create mode 100644 exampleAiApp01/app/src/main/res/values/strings.xml create mode 100644 exampleAiApp01/app/src/main/res/values/themes.xml create mode 100644 exampleAiApp01/build.gradle.kts create mode 100644 exampleAiApp01/gradle.properties create mode 100644 exampleAiApp01/gradle/wrapper/gradle-wrapper.properties create mode 100644 exampleAiApp01/settings.gradle.kts diff --git a/docs/api_expert_generate_3_open.md b/docs/api_expert_generate_3_open.md new file mode 100644 index 0000000..4d640bd --- /dev/null +++ b/docs/api_expert_generate_3_open.md @@ -0,0 +1,108 @@ +# 智能提示词优化3号专家 - 对外接口文档 + +供 Android 等外部应用调用的 REST API。 + +## 接口地址 + +``` +POST http://101.43.95.130:5002/api/open/expert-generate-3 +``` + +## 请求 + +- **Method**: POST +- **Content-Type**: application/json + +### 请求体参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| input_text | string | 是 | 用户需求描述 | +| temperature | number | 否 | 生成随机性,0-2,默认 0.7 | +| max_tokens | int | 否 | 最大生成 token 数,100-4000,默认 1000 | +| timeout | int | 否 | 超时时间(秒),10-300,默认 60 | +| uid | int | 否 | 用户ID,用于历史记录归属,不传则使用默认用户 | + +### 示例 + +```json +{ + "input_text": "android内存溢出分析", + "temperature": 0.7, + "max_tokens": 1000, + "timeout": 60, + "uid": 1 +} +``` + +## 响应 + +### 成功 (code=200) + +```json +{ + "code": 200, + "message": "success", + "data": { + "intent_analysis": { + "core_intent": "技术", + "domain": "xxx", + "key_requirements": ["..."], + "expected_output": "...", + "constraints": ["..."] + }, + "generated_prompt": "生成的完整提示词文本" + } +} +``` + +### 失败 + +```json +{ + "code": 400, + "message": "错误描述", + "data": null +} +``` + +常见 code:400 参数错误,429 重复提交,500 服务器错误。 + +## Android 调用示例 (Kotlin + Retrofit) + +```kotlin +// 请求体 +data class ExpertGenerate3Request( + val input_text: String, + val temperature: Float? = 0.7f, + val max_tokens: Int? = 1000, + val timeout: Int? = 60, + val uid: Int? = null +) + +// 响应体 +data class ExpertGenerate3Response( + val code: Int, + val message: String, + val data: Data? +) +data class Data( + val intent_analysis: IntentAnalysis, + val generated_prompt: String +) + +// 使用 +val api = Retrofit.Builder() + .baseUrl("http://101.43.95.130:5002/") + .addConverterFactory(GsonConverterFactory.create()) + .build() + .create(YourApi::class.java) + +api.expertGenerate3(ExpertGenerate3Request(input_text = "android内存溢出分析")) +``` + +## 注意事项 + +- 项目已启用 CORS,支持跨域调用 +- 对外接口不做 8 秒内重复提交校验,由客户端自行控制 +- 建议在客户端增加防重复点击、超时重试等逻辑 diff --git a/exampleAiApp01/README.md b/exampleAiApp01/README.md new file mode 100644 index 0000000..935743b --- /dev/null +++ b/exampleAiApp01/README.md @@ -0,0 +1,29 @@ +# 提示词智能优化 Android App + +调用提示词大师 3 号专家接口,实现智能提示词生成。 + +## 环境 + +- Android Studio(推荐使用 AGP 8.7+、Gradle 8.9) +- minSdk 24,targetSdk 34 +- Java 17 + +## 接口 + +- 地址:`POST http://101.43.95.130:5002/api/open/expert-generate-3` +- 参数:`input_text`(必填)、`temperature`、`max_tokens`、`timeout`、`uid` + +## 构建 + +```bash +cd exampleAiApp01 +./gradlew assembleDebug +``` + +或在 Android Studio 中打开 `exampleAiApp01` 目录,直接运行到真机或模拟器。 + +## 注意事项 + +- 需配置网络权限,并允许明文 HTTP(101.43.95.130 为 HTTP) +- 确保设备可访问 `101.43.95.130:5002` +- 如缺少启动图标,可在 Android Studio 中通过 `File > New > Image Asset` 生成 diff --git a/exampleAiApp01/app/build.gradle.kts b/exampleAiApp01/app/build.gradle.kts new file mode 100644 index 0000000..b579446 --- /dev/null +++ b/exampleAiApp01/app/build.gradle.kts @@ -0,0 +1,46 @@ +plugins { + id("com.android.application") +} + +android { + namespace = "com.example.promptoptimizer" + compileSdk = 34 + + defaultConfig { + applicationId = "com.example.promptoptimizer" + minSdk = 24 + targetSdk = 34 + versionCode = 1 + versionName = "1.0" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + buildFeatures { + viewBinding = true + } +} + +dependencies { + implementation("androidx.core:core-ktx:1.12.0") + implementation("androidx.appcompat:appcompat:1.6.1") + implementation("com.google.android.material:material:1.11.0") + implementation("androidx.constraintlayout:constraintlayout:2.1.4") + + // Retrofit + implementation("com.squareup.retrofit2:retrofit:2.9.0") + implementation("com.squareup.retrofit2:converter-gson:2.9.0") + implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") +} + diff --git a/exampleAiApp01/app/proguard-rules.pro b/exampleAiApp01/app/proguard-rules.pro new file mode 100644 index 0000000..92cd3ca --- /dev/null +++ b/exampleAiApp01/app/proguard-rules.pro @@ -0,0 +1,3 @@ +-keepattributes Signature +-keepattributes *Annotation* +-keep class com.example.promptoptimizer.api.** { *; } diff --git a/exampleAiApp01/app/src/main/AndroidManifest.xml b/exampleAiApp01/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6a1e966 --- /dev/null +++ b/exampleAiApp01/app/src/main/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + diff --git a/exampleAiApp01/app/src/main/java/com/example/promptoptimizer/MainActivity.java b/exampleAiApp01/app/src/main/java/com/example/promptoptimizer/MainActivity.java new file mode 100644 index 0000000..54d6c52 --- /dev/null +++ b/exampleAiApp01/app/src/main/java/com/example/promptoptimizer/MainActivity.java @@ -0,0 +1,146 @@ +package com.example.promptoptimizer; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.os.Bundle; +import android.view.View; +import android.widget.EditText; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; + +import com.example.promptoptimizer.api.ExpertGenerate3Api; +import com.example.promptoptimizer.model.ExpertGenerate3Request; +import com.example.promptoptimizer.model.ExpertGenerate3Response; +import com.google.android.material.button.MaterialButton; +import com.google.android.material.card.MaterialCardView; + +import java.util.Arrays; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * 提示词智能优化 - 主界面 + */ +public class MainActivity extends AppCompatActivity { + + private EditText etInput; + private MaterialButton btnGenerate; + private ProgressBar progressBar; + private TextView tvLoading; + private MaterialCardView cardResult; + private TextView tvIntent; + private TextView tvPrompt; + private MaterialButton btnCopy; + + private boolean isSubmitting = false; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + etInput = findViewById(R.id.etInput); + btnGenerate = findViewById(R.id.btnGenerate); + progressBar = findViewById(R.id.progressBar); + tvLoading = findViewById(R.id.tvLoading); + cardResult = findViewById(R.id.cardResult); + tvIntent = findViewById(R.id.tvIntent); + tvPrompt = findViewById(R.id.tvPrompt); + btnCopy = findViewById(R.id.btnCopy); + + btnGenerate.setOnClickListener(v -> doGenerate()); + btnCopy.setOnClickListener(v -> copyPrompt()); + } + + private void doGenerate() { + if (isSubmitting) return; + + String input = etInput.getText() != null ? etInput.getText().toString().trim() : ""; + if (input.isEmpty()) { + Toast.makeText(this, R.string.error_empty, Toast.LENGTH_SHORT).show(); + return; + } + + isSubmitting = true; + progressBar.setVisibility(View.VISIBLE); + tvLoading.setVisibility(View.VISIBLE); + btnGenerate.setEnabled(false); + cardResult.setVisibility(View.GONE); + + ExpertGenerate3Request request = new ExpertGenerate3Request(input); + ExpertGenerate3Api api = RetrofitClient.getApi(); + + api.generate(request).enqueue(new Callback() { + @Override + public void onResponse(Call call, + Response response) { + isSubmitting = false; + progressBar.setVisibility(View.GONE); + tvLoading.setVisibility(View.GONE); + btnGenerate.setEnabled(true); + + if (response.isSuccessful() && response.body() != null) { + ExpertGenerate3Response body = response.body(); + if (body.getCode() == 200 && body.getData() != null) { + showResult(body); + } else { + Toast.makeText(MainActivity.this, + body.getMessage() != null ? body.getMessage() : getString(R.string.error_network), + Toast.LENGTH_LONG).show(); + } + } else { + Toast.makeText(MainActivity.this, R.string.error_network, Toast.LENGTH_LONG).show(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + isSubmitting = false; + progressBar.setVisibility(View.GONE); + tvLoading.setVisibility(View.GONE); + btnGenerate.setEnabled(true); + Toast.makeText(MainActivity.this, R.string.error_network + ": " + t.getMessage(), + Toast.LENGTH_LONG).show(); + } + }); + } + + private void showResult(ExpertGenerate3Response response) { + ExpertGenerate3Response.ResponseData data = response.getData(); + if (data == null) return; + + StringBuilder intentSb = new StringBuilder(); + ExpertGenerate3Response.IntentAnalysis ia = data.getIntentAnalysis(); + if (ia != null) { + intentSb.append("核心意图:").append(ia.getCoreIntent()).append("\n"); + intentSb.append("专业领域:").append(ia.getDomain()).append("\n"); + intentSb.append("预期输出:").append(ia.getExpectedOutput()).append("\n"); + if (ia.getKeyRequirements() != null && ia.getKeyRequirements().length > 0) { + intentSb.append("关键需求:\n").append(Arrays.toString(ia.getKeyRequirements())).append("\n"); + } + if (ia.getConstraints() != null && ia.getConstraints().length > 0) { + intentSb.append("约束条件:\n").append(Arrays.toString(ia.getConstraints())); + } + } + tvIntent.setText(intentSb.toString()); + tvPrompt.setText(data.getGeneratedPrompt() != null ? data.getGeneratedPrompt() : ""); + cardResult.setVisibility(View.VISIBLE); + } + + private void copyPrompt() { + String text = tvPrompt.getText() != null ? tvPrompt.getText().toString() : ""; + if (text.isEmpty()) return; + + ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); + if (cm != null) { + cm.setPrimaryClip(ClipData.newPlainText("prompt", text)); + Toast.makeText(this, R.string.toast_copied, Toast.LENGTH_SHORT).show(); + } + } +} diff --git a/exampleAiApp01/app/src/main/java/com/example/promptoptimizer/RetrofitClient.java b/exampleAiApp01/app/src/main/java/com/example/promptoptimizer/RetrofitClient.java new file mode 100644 index 0000000..ca0589f --- /dev/null +++ b/exampleAiApp01/app/src/main/java/com/example/promptoptimizer/RetrofitClient.java @@ -0,0 +1,46 @@ +package com.example.promptoptimizer; + +import com.example.promptoptimizer.api.ExpertGenerate3Api; + +import okhttp3.OkHttpClient; +import okhttp3.logging.HttpLoggingInterceptor; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +import java.util.concurrent.TimeUnit; + +public class RetrofitClient { + + private static final String BASE_URL = "http://101.43.95.130:5002/"; + + private static Retrofit retrofit; + private static ExpertGenerate3Api api; + + public static ExpertGenerate3Api getApi() { + if (api == null) { + api = getRetrofit().create(ExpertGenerate3Api.class); + } + return api; + } + + private static Retrofit getRetrofit() { + if (retrofit == null) { + HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); + interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); + + OkHttpClient client = new OkHttpClient.Builder() + .connectTimeout(90, TimeUnit.SECONDS) + .readTimeout(90, TimeUnit.SECONDS) + .writeTimeout(90, TimeUnit.SECONDS) + .addInterceptor(interceptor) + .build(); + + retrofit = new Retrofit.Builder() + .baseUrl(BASE_URL) + .client(client) + .addConverterFactory(GsonConverterFactory.create()) + .build(); + } + return retrofit; + } +} diff --git a/exampleAiApp01/app/src/main/java/com/example/promptoptimizer/api/ExpertGenerate3Api.java b/exampleAiApp01/app/src/main/java/com/example/promptoptimizer/api/ExpertGenerate3Api.java new file mode 100644 index 0000000..34330f8 --- /dev/null +++ b/exampleAiApp01/app/src/main/java/com/example/promptoptimizer/api/ExpertGenerate3Api.java @@ -0,0 +1,17 @@ +package com.example.promptoptimizer.api; + +import com.example.promptoptimizer.model.ExpertGenerate3Response; +import com.example.promptoptimizer.model.ExpertGenerate3Request; + +import retrofit2.Call; +import retrofit2.http.Body; +import retrofit2.http.POST; + +/** + * 智能提示词优化3号专家 API + */ +public interface ExpertGenerate3Api { + + @POST("api/open/expert-generate-3") + Call generate(@Body ExpertGenerate3Request request); +} diff --git a/exampleAiApp01/app/src/main/java/com/example/promptoptimizer/model/ExpertGenerate3Request.java b/exampleAiApp01/app/src/main/java/com/example/promptoptimizer/model/ExpertGenerate3Request.java new file mode 100644 index 0000000..eee55b3 --- /dev/null +++ b/exampleAiApp01/app/src/main/java/com/example/promptoptimizer/model/ExpertGenerate3Request.java @@ -0,0 +1,71 @@ +package com.example.promptoptimizer.model; + +import com.google.gson.annotations.SerializedName; + +/** + * 请求体 + */ +public class ExpertGenerate3Request { + + @SerializedName("input_text") + private String inputText; + + @SerializedName("temperature") + private Float temperature; + + @SerializedName("max_tokens") + private Integer maxTokens; + + @SerializedName("timeout") + private Integer timeout; + + @SerializedName("uid") + private Integer uid; + + public ExpertGenerate3Request(String inputText) { + this.inputText = inputText; + this.temperature = 0.7f; + this.maxTokens = 1000; + this.timeout = 60; + } + + public String getInputText() { + return inputText; + } + + public void setInputText(String inputText) { + this.inputText = inputText; + } + + public Float getTemperature() { + return temperature; + } + + public void setTemperature(Float temperature) { + this.temperature = temperature; + } + + public Integer getMaxTokens() { + return maxTokens; + } + + public void setMaxTokens(Integer maxTokens) { + this.maxTokens = maxTokens; + } + + public Integer getTimeout() { + return timeout; + } + + public void setTimeout(Integer timeout) { + this.timeout = timeout; + } + + public Integer getUid() { + return uid; + } + + public void setUid(Integer uid) { + this.uid = uid; + } +} diff --git a/exampleAiApp01/app/src/main/java/com/example/promptoptimizer/model/ExpertGenerate3Response.java b/exampleAiApp01/app/src/main/java/com/example/promptoptimizer/model/ExpertGenerate3Response.java new file mode 100644 index 0000000..4c50840 --- /dev/null +++ b/exampleAiApp01/app/src/main/java/com/example/promptoptimizer/model/ExpertGenerate3Response.java @@ -0,0 +1,120 @@ +package com.example.promptoptimizer.model; + +import com.google.gson.annotations.SerializedName; + +/** + * 响应体 + */ +public class ExpertGenerate3Response { + + private int code; + private String message; + + @SerializedName("data") + private ResponseData data; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public ResponseData getData() { + return data; + } + + public void setData(ResponseData data) { + this.data = data; + } + + public static class ResponseData { + @SerializedName("intent_analysis") + private IntentAnalysis intentAnalysis; + + @SerializedName("generated_prompt") + private String generatedPrompt; + + public IntentAnalysis getIntentAnalysis() { + return intentAnalysis; + } + + public void setIntentAnalysis(IntentAnalysis intentAnalysis) { + this.intentAnalysis = intentAnalysis; + } + + public String getGeneratedPrompt() { + return generatedPrompt; + } + + public void setGeneratedPrompt(String generatedPrompt) { + this.generatedPrompt = generatedPrompt; + } + } + + public static class IntentAnalysis { + @SerializedName("core_intent") + private String coreIntent; + + @SerializedName("domain") + private String domain; + + @SerializedName("key_requirements") + private String[] keyRequirements; + + @SerializedName("expected_output") + private String expectedOutput; + + @SerializedName("constraints") + private String[] constraints; + + public String getCoreIntent() { + return coreIntent; + } + + public void setCoreIntent(String coreIntent) { + this.coreIntent = coreIntent; + } + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + public String[] getKeyRequirements() { + return keyRequirements; + } + + public void setKeyRequirements(String[] keyRequirements) { + this.keyRequirements = keyRequirements; + } + + public String getExpectedOutput() { + return expectedOutput; + } + + public void setExpectedOutput(String expectedOutput) { + this.expectedOutput = expectedOutput; + } + + public String[] getConstraints() { + return constraints; + } + + public void setConstraints(String[] constraints) { + this.constraints = constraints; + } + } +} diff --git a/exampleAiApp01/app/src/main/res/drawable/edit_bg.xml b/exampleAiApp01/app/src/main/res/drawable/edit_bg.xml new file mode 100644 index 0000000..63379e6 --- /dev/null +++ b/exampleAiApp01/app/src/main/res/drawable/edit_bg.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/exampleAiApp01/app/src/main/res/drawable/ic_launcher_foreground.xml b/exampleAiApp01/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..76b0e86 --- /dev/null +++ b/exampleAiApp01/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,10 @@ + + + + diff --git a/exampleAiApp01/app/src/main/res/layout/activity_main.xml b/exampleAiApp01/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..cb597d3 --- /dev/null +++ b/exampleAiApp01/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/exampleAiApp01/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/exampleAiApp01/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..5ed0a2d --- /dev/null +++ b/exampleAiApp01/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/exampleAiApp01/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/exampleAiApp01/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..5ed0a2d --- /dev/null +++ b/exampleAiApp01/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/exampleAiApp01/app/src/main/res/values/colors.xml b/exampleAiApp01/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..5a56c1b --- /dev/null +++ b/exampleAiApp01/app/src/main/res/values/colors.xml @@ -0,0 +1,5 @@ + + + #F8FAFC + #1E3A8A + diff --git a/exampleAiApp01/app/src/main/res/values/strings.xml b/exampleAiApp01/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..094726c --- /dev/null +++ b/exampleAiApp01/app/src/main/res/values/strings.xml @@ -0,0 +1,14 @@ + + + 提示词智能优化 + 请描述您的需求,系统将进行专业分析并生成高质量提示词 + 生成专家提示词 + 生成结果 + 需求分析 + 生成的专家提示词 + 复制提示词 + 已复制到剪贴板 + 正在分析需求并生成专业提示词… + 网络请求失败,请检查网络后重试 + 请输入您的需求 + diff --git a/exampleAiApp01/app/src/main/res/values/themes.xml b/exampleAiApp01/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..685b7e1 --- /dev/null +++ b/exampleAiApp01/app/src/main/res/values/themes.xml @@ -0,0 +1,8 @@ + + + + diff --git a/exampleAiApp01/build.gradle.kts b/exampleAiApp01/build.gradle.kts new file mode 100644 index 0000000..a0dd15f --- /dev/null +++ b/exampleAiApp01/build.gradle.kts @@ -0,0 +1,3 @@ +plugins { + id("com.android.application") version "8.7.3" apply false +} diff --git a/exampleAiApp01/gradle.properties b/exampleAiApp01/gradle.properties new file mode 100644 index 0000000..f0a2e55 --- /dev/null +++ b/exampleAiApp01/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +android.useAndroidX=true +kotlin.code.style=official +android.nonTransitiveRClass=true diff --git a/exampleAiApp01/gradle/wrapper/gradle-wrapper.properties b/exampleAiApp01/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..09523c0 --- /dev/null +++ b/exampleAiApp01/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/exampleAiApp01/settings.gradle.kts b/exampleAiApp01/settings.gradle.kts new file mode 100644 index 0000000..70a134c --- /dev/null +++ b/exampleAiApp01/settings.gradle.kts @@ -0,0 +1,17 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "PromptOptimizer" +include(":app") diff --git a/logs/app.log b/logs/app.log index 0835bd1..4f53c28 100644 --- a/logs/app.log +++ b/logs/app.log @@ -2927,3 +2927,4 @@ werkzeug.routing.exceptions.BuildError: Could not build url for endpoint 'expert [in /home/renjianbo/aitsc/src/flask_prompt_master/__init__.py:120] 2026-02-28 22:15:25,968 INFO: 应用启动 [in /home/renjianbo/aitsc/config/base.py:82] 2026-02-28 22:22:12,598 INFO: 应用启动 [in /home/renjianbo/aitsc/config/base.py:82] +2026-03-01 22:57:49,275 INFO: 应用启动 [in /home/renjianbo/aitsc/config/base.py:82] diff --git a/logs/gunicorn.pid b/logs/gunicorn.pid index 85fb85f..e87c90b 100644 --- a/logs/gunicorn.pid +++ b/logs/gunicorn.pid @@ -1 +1 @@ -22948 +21107 diff --git a/logs/gunicorn_access.log b/logs/gunicorn_access.log index ef8a059..75eb7eb 100644 --- a/logs/gunicorn_access.log +++ b/logs/gunicorn_access.log @@ -15248,3 +15248,6 @@ 206.168.34.39 - - [01/Mar/2026:01:05:25 +0800] "PRI * HTTP/2.0" 404 207 "-" "-" 828 206.168.34.39 - - [01/Mar/2026:01:05:26 +0800] "GET /favicon.ico HTTP/1.1" 404 207 "-" "Mozilla/5.0 (compatible; CensysInspect/1.1; +https://about.censys.io/)" 806 206.168.34.39 - - [01/Mar/2026:01:05:45 +0800] "GET /security.txt HTTP/1.1" 404 207 "-" "Mozilla/5.0 (compatible; CensysInspect/1.1; +https://about.censys.io/)" 659 +123.139.40.200 - - [01/Mar/2026:22:58:01 +0800] "GET / HTTP/1.1" 200 216259 "http://101.43.95.130:5002/expert-generate-3" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0" 712510 +123.139.40.200 - - [01/Mar/2026:22:58:01 +0800] "GET /static/js/interactions.js HTTP/1.1" 404 207 "http://101.43.95.130:5002/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0" 5764 +123.139.40.200 - - [01/Mar/2026:22:58:02 +0800] "GET /api/check-login HTTP/1.1" 200 35 "http://101.43.95.130:5002/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0" 5242 diff --git a/logs/gunicorn_error.log b/logs/gunicorn_error.log index 05f84f4..1efceda 100644 --- a/logs/gunicorn_error.log +++ b/logs/gunicorn_error.log @@ -10587,3 +10587,36 @@ werkzeug.routing.exceptions.BuildError: Could not build url for endpoint 'expert [2026-03-01 02:01:44 +0800] [31755] [ERROR] Worker (pid:696) was sent SIGTERM! [2026-03-01 02:01:44 +0800] [31755] [ERROR] Worker (pid:831) was sent SIGTERM! [2026-03-01 02:01:44 +0800] [31755] [INFO] Shutting down: Master +[2026-03-01 22:57:51 +0800] [21107] [INFO] Starting gunicorn 21.2.0 +[2026-03-01 22:57:51 +0800] [21107] [INFO] Gunicorn服务器启动中... +[2026-03-01 22:57:51 +0800] [21107] [INFO] Listening at: http://0.0.0.0:5002 (21107) +[2026-03-01 22:57:51 +0800] [21107] [INFO] Using worker: sync +[2026-03-01 22:57:51 +0800] [21107] [INFO] 工作进程 [booting] 即将启动 +[2026-03-01 22:57:51 +0800] [21286] [INFO] Booting worker with pid: 21286 +[2026-03-01 22:57:51 +0800] [21286] [INFO] 工作进程 21286 已启动 +[2026-03-01 22:57:51 +0800] [21286] [INFO] 工作进程 21286 初始化完成 +[2026-03-01 22:57:51 +0800] [21107] [INFO] 工作进程 [booting] 即将启动 +[2026-03-01 22:57:51 +0800] [21293] [INFO] Booting worker with pid: 21293 +[2026-03-01 22:57:51 +0800] [21293] [INFO] 工作进程 21293 已启动 +[2026-03-01 22:57:51 +0800] [21293] [INFO] 工作进程 21293 初始化完成 +[2026-03-01 22:57:51 +0800] [21107] [INFO] 工作进程 [booting] 即将启动 +[2026-03-01 22:57:51 +0800] [21294] [INFO] Booting worker with pid: 21294 +[2026-03-01 22:57:51 +0800] [21294] [INFO] 工作进程 21294 已启动 +[2026-03-01 22:57:51 +0800] [21294] [INFO] 工作进程 21294 初始化完成 +[2026-03-01 22:57:51 +0800] [21107] [INFO] 工作进程 [booting] 即将启动 +[2026-03-01 22:57:51 +0800] [21295] [INFO] Booting worker with pid: 21295 +[2026-03-01 22:57:51 +0800] [21295] [INFO] 工作进程 21295 已启动 +[2026-03-01 22:57:51 +0800] [21295] [INFO] 工作进程 21295 初始化完成 +[2026-03-01 22:57:51 +0800] [21107] [INFO] 工作进程 [booting] 即将启动 +[2026-03-01 22:57:51 +0800] [21296] [INFO] Booting worker with pid: 21296 +[2026-03-01 22:57:51 +0800] [21296] [INFO] 工作进程 21296 已启动 +[2026-03-01 22:57:51 +0800] [21296] [INFO] 工作进程 21296 初始化完成 +[2026-03-01 23:03:09 +0800] [21107] [CRITICAL] WORKER TIMEOUT (pid:21296) +[2026-03-01 23:03:09 +0800] [21296] [INFO] 工作进程 21296 异常退出 +[2026-03-01 23:03:09 +0800] [21296] [INFO] Worker exiting (pid: 21296) +[2026-03-01 23:03:09 +0800] [21107] [ERROR] Worker (pid:21296) exited with code 1 +[2026-03-01 23:03:09 +0800] [21107] [ERROR] Worker (pid:21296) exited with code 1. +[2026-03-01 23:03:09 +0800] [21107] [INFO] 工作进程 [booting] 即将启动 +[2026-03-01 23:03:09 +0800] [2175] [INFO] Booting worker with pid: 2175 +[2026-03-01 23:03:09 +0800] [2175] [INFO] 工作进程 2175 已启动 +[2026-03-01 23:03:09 +0800] [2175] [INFO] 工作进程 2175 初始化完成 diff --git a/src/flask_prompt_master/routes/__pycache__/expert_generate_3.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/expert_generate_3.cpython-312.pyc index facd71bbdb0f53e5eb7b883c874a6097c3e411f9..4fadad706dad362287888407a4d89e2de74dadf2 100644 GIT binary patch delta 2593 zcmah~ZA@EL7`~^sx1Y3yenVR*w2XGZ_?+y+eIV$fTc&)>jIo6+GWsVw&I$^N3A#%b>hzTT>G*u2+6?*m`vHh(>UntRkw{ zjM$VraU4-GPXdX0S%odkBN}kgrf!5dRqn)gK+2)pPcsOaCp>`LSQ_D(2f$4-zYW~H z4cr28JHdHIeWH+I$ZDd_Lsv5opcl#NZRpl*=r*GM7rGid7{~byMHYyFUCbJHGfg>T zF{lZOdz2|h2^33t-%_F+wde{5Rk8+`v9Ne4^-suJqQQP<9Oa}^qTM4Qbl})QunxAi76YqL-)_eDms@SJn|-yq@N0OX(Hjjq51Q zN{6#W&=Y;Uh5AfoqK1_^XF-1DwzEpm>p8q%nJDop6Rv{OVtG4v&JLq!Bt~KwMJaSe zhYxMis368maA3E39jQ5D5CinFVsI2mf>=qM_rK-vdL1;hY@UhcM?D`0uD2_IpY z#DtGBoe_lEZ`P8SSe95i6yi8w)Ff6#5iyVg`kX5V)Er#l1?2~quWEw}KCu%~w&4BD z7C%YZcno5-ShG+&&*$uN;eT{P3*8`=cn3|aD_q#KNhz-{L`8V$Ox^s(;K)U!=t-Sv zuo7!(`-r*3`kf;N*XrCP-K|{n?5f8-%s>#a5@Df%@n@7^shJ zNp-Rr!&{JB@ndu@`4BNHbsk5nOAP1Ve?Zm4iM(vSZ0_3F#}K9+UtfT>?=fh*b7&?P zex5~wrNiTE%EKAs#`zv@3<2k}EDjKl0OHQ#^+EA`#x2(Ul=ZPjVrIjNIL31lT`9;h z9z#!fLU|tN99Huaur&XJbubTWc)gnYa$P!^cYih-<0z#<+|D_BT%8&F@cxlwP#@)Q zRH5wlrF*kR92veCk^1q76p0S5uiuVDSqYhPG;0{{AMeA-p-3VXdjN0PLlI(PbMOJn zYH@5hk{rPgX)hnrk7KL`K7h)nzN9a#&I-dxF>)cR8;+z>{n1EDIsg$8{R>iFEFJe! zI+B$N`XvkV6792eoQf05&!wNZ!-DiIJv~RodhS809a3(U{i5#zb)*sm+^9_V>xVZU zeD+beMOpTTompYskD$08SBz^ZGr!-j1Om0zNzmVgU+Mw;UBAlxp*g3V4@4$@bo#CiO%2V}W}NkD z<7!RIQcc@*WajvaGxW7BZCrB}&je;ub4}NcnX=}Lb1%d=yjOdtdgr_u$DXudHPpBi zIy~JqQ!?H6MSI$?=5Wv0W(Vei*A1D{ri`N*LafDCtEZ}GVi{{FtzE4MFIDWF4opU; zYd&vuq_t~S$K?6hz|6p0OQxhcW35SRm9GLfk!SIZUOeTXU%F637X)VoqBfMvx&y(@10DKEcLUVqBP-!DR--**Y8 zyvp05CU+lnMoNIlYA+fbxCl=3zRrS#2aS8k3Rm0hflT7^Py2 vipx~gfXE6GjCDk6q=rdlDeObns5m!)Tii{z{| zCcaeC*o;OWc+ppghVW$42X9f63UnJEnoW%_#^{q8Uo`Q-e|8xt1mYz7|1A!DcdaHFcq{Jvtdq#S=OaWY6UCy`fv*yt?V^h3`??| ziybav*?@@nDo7Ofp@aopRYev%qMdmI)>i4gZdioh87uLOpsOx~GB(3zSeI}bui0o% z-WCY)8n#v7!u~C6LWY(2crHoB64uS6lAn2gh#!#70g~OYvQK?(cEzWR(_YZzmr+DP zSy;kdD8fNfje`Ocbta4uIMPi532aymJBMHEGa(4$A`4bjHSN1VM~)+AiuVHrMe-8w zpDHV_kT%1@f8i3e*D)MC!RMqD^EACAt|wpS zu{22>hQ1=Cn`cCO0Zd#-lh?T|me?J?yQ+n>Lh7BQ4O;WaWYi(r!8&~b_LJZ2P$;iW zekBKaH~Om#MU)q?4`)mv)vPAqjwo*^6Ntze;LDhv6}Rh=elBwi&FgA84U7(ni(s+; zVc_uHN8p#yiadpuF}OS_?BSt7c<5N}*q4>6nA*dLrg%i7k;k2w+V}lkyjCotIOUn( zk$4JN&8J{l{s*i72$shE!tMDwDJP|31*av9pxq!P6(^=7(y=(of}s$bseXsWYEo^# z@vtMNoOv!qwAq|(PD`ib2`!yds5ZBt>2bQKYdI^Op3_o`l>Jz<65!LPmvf@>yRv?X z@1Nr2GP_axNo(TO{Q6~Z`d65~h*`hDb-Z-?MIgDNx%kR8nwrt()A}&$4gQQ{ED&nL z-RzlAgxw0=#!qZl)Y-7RG-q9izdoCalbl_TFJGIUUjQGTtY0ye0uKASzP0=oY~F`o zdJ;aIZ=yde6HIQ<*uM>Tv1j|U#u&B+9(w%`U7qc-@FRRP7DXQoDL}ty9f|_`s(#o3 z?3=FY=lamMWkXJ2-vw=)MustH?zIfr#|F^%(XN;s?S#ufw9}`K^~<}C`YXNiZYSpZ zE)&Ridy8SeC%2A8<-HCr-|OV^y{MV*`{h`4673DxV;1?o^=u5w_xmlN&SEo2vKCOI ztlb{#mb2xaSeu*;=e2ESF6qu|qxSJWIXl=f-XlL~$FP6UV;=8gpP%XWO+gOy*MQ`# zv#CU4dOnepQfd7vQ=0FF`3E3p)#jI`_0+r`;--B1b&Zn+PHu3r!hUad*YJ$$9h~t0 n4!s#j&UPN!V{uj+&_CF&Yf-WHd5ksumyDzs{!_{y^49+Wc|?!p diff --git a/src/flask_prompt_master/routes/expert_generate_3.py b/src/flask_prompt_master/routes/expert_generate_3.py index 1079400..dd66cc0 100644 --- a/src/flask_prompt_master/routes/expert_generate_3.py +++ b/src/flask_prompt_master/routes/expert_generate_3.py @@ -140,6 +140,84 @@ def _resolve_user_id(): return 1 +def _do_generate(raw_input, temperature, max_tokens, timeout, user_id, skip_dedup=False): + """核心生成逻辑,供 Web API 和对外接口共用""" + if not skip_dedup: + req_key = (user_id, hashlib.md5(raw_input.encode()).hexdigest()) + now_ts = time.time() + if req_key in _dedup_cache and (now_ts - _dedup_cache[req_key]) < 8: + return {'code': 429, 'message': '请勿重复提交,请稍后再试', 'data': None} + _dedup_cache[req_key] = now_ts + if len(_dedup_cache) > 500: + _dedup_cache.clear() + + resp1 = _llm_client.chat.completions.create( + model="deepseek-chat", + messages=[ + {"role": "system", "content": INTENT_PROMPT_3}, + {"role": "user", "content": raw_input} + ], + temperature=0.1, + timeout=timeout + ) + intent_raw = (resp1.choices[0].message.content or "").strip() + intent_raw = intent_raw.replace('```json', '').replace('```', '').strip() + try: + intent_data = json.loads(intent_raw) + for field in ['core_intent', 'domain', 'key_requirements', 'expected_output', 'constraints', 'keywords']: + if field not in intent_data: + raise ValueError("缺少字段: " + field) + if intent_data['core_intent'] not in ('技术', '创意', '分析', '咨询'): + intent_data['core_intent'] = '技术' + for arr_field in ['key_requirements', 'constraints', 'keywords']: + v = intent_data.get(arr_field) + if not isinstance(v, list) or len(v) == 0: + intent_data[arr_field] = ['未指定'] + except json.JSONDecodeError: + raise ValueError("意图分析格式有误") + except ValueError: + raise + + tpl = EXPERT_TEMPLATES_3.get(intent_data['core_intent'], FALLBACK_TEMPLATE_3) + analysis_str = json.dumps(intent_data, ensure_ascii=False, indent=2) + resp2 = _llm_client.chat.completions.create( + model="deepseek-chat", + messages=[ + {"role": "system", "content": tpl.format(analysis=analysis_str)}, + {"role": "user", "content": raw_input} + ], + temperature=temperature, + max_tokens=max_tokens, + timeout=timeout + ) + result_prompt = (resp2.choices[0].message.content or "").strip() + if not result_prompt: + raise ValueError("生成结果为空") + + try: + db.session.add(Prompt(input_text=raw_input, generated_text=result_prompt, user_id=user_id)) + db.session.commit() + except Exception as e: + db.session.rollback() + logger.warning("3号专家 保存 Prompt 失败: %s", e) + try: + PromptHistory.add_history( + user_id=user_id, + original_input=raw_input, + generated_prompt=result_prompt, + template_name=TEMPLATE_NAME_3 + ) + UserStatistics.update_statistics(user_id) + except Exception as e: + logger.warning("3号专家 保存历史失败: %s", e) + + return { + 'code': 200, + 'message': 'success', + 'data': {'intent_analysis': intent_data, 'generated_prompt': result_prompt} + } + + @expert_generate_3_bp.route('/expert-generate-3', methods=['GET']) def expert_generate_3_page(): """智能提示词优化3号专家 - 页面""" @@ -148,7 +226,20 @@ def expert_generate_3_page(): @expert_generate_3_bp.route('/api/expert-generate-3/generate', methods=['POST']) def expert_generate_3_api(): - """智能提示词优化3号专家 - 两阶段生成 API,含历史记录""" + """智能提示词优化3号专家 - 两阶段生成 API(Web 用),含历史记录""" + return _handle_generate_api(skip_dedup=False, user_id=None) + + +@expert_generate_3_bp.route('/api/open/expert-generate-3', methods=['POST']) +def expert_generate_3_open_api(): + """ + 智能提示词优化3号专家 - 对外接口,供 Android 等外部应用调用。 + POST JSON: input_text(必填), temperature, max_tokens, timeout, uid(可选) + """ + return _handle_generate_api(skip_dedup=True, user_id=None) + + +def _handle_generate_api(skip_dedup=False, user_id=None): try: if not request.is_json: return jsonify({'code': 400, 'message': '请求必须是JSON格式', 'data': None}) @@ -167,79 +258,16 @@ def expert_generate_3_api(): timeout = int(timeout) if timeout is not None else 60 timeout = max(10, min(300, timeout)) - uid = _resolve_user_id() - req_key = (uid, hashlib.md5(raw_input.encode()).hexdigest()) - now_ts = time.time() - if req_key in _dedup_cache and (now_ts - _dedup_cache[req_key]) < 8: - return jsonify({'code': 429, 'message': '请勿重复提交,请稍后再试', 'data': None}) - _dedup_cache[req_key] = now_ts - if len(_dedup_cache) > 500: - _dedup_cache.clear() + uid = user_id if user_id is not None else payload.get('uid') + if uid is not None: + uid = int(uid) + else: + uid = _resolve_user_id() - resp1 = _llm_client.chat.completions.create( - model="deepseek-chat", - messages=[ - {"role": "system", "content": INTENT_PROMPT_3}, - {"role": "user", "content": raw_input} - ], - temperature=0.1, - timeout=timeout - ) - intent_raw = (resp1.choices[0].message.content or "").strip() - intent_raw = intent_raw.replace('```json', '').replace('```', '').strip() - try: - intent_data = json.loads(intent_raw) - for field in ['core_intent', 'domain', 'key_requirements', 'expected_output', 'constraints', 'keywords']: - if field not in intent_data: - raise ValueError("缺少字段: " + field) - if intent_data['core_intent'] not in ('技术', '创意', '分析', '咨询'): - intent_data['core_intent'] = '技术' - for arr_field in ['key_requirements', 'constraints', 'keywords']: - v = intent_data.get(arr_field) - if not isinstance(v, list) or len(v) == 0: - intent_data[arr_field] = ['未指定'] - except json.JSONDecodeError as e: - logger.error("3号专家 JSON解析失败: %s", e) - return jsonify({'code': 500, 'message': '意图分析格式有误,请重试', 'data': None}) - except ValueError as e: - logger.error("3号专家 数据验证失败: %s", e) - return jsonify({'code': 500, 'message': str(e), 'data': None}) - tpl = EXPERT_TEMPLATES_3.get(intent_data['core_intent'], FALLBACK_TEMPLATE_3) - analysis_str = json.dumps(intent_data, ensure_ascii=False, indent=2) - resp2 = _llm_client.chat.completions.create( - model="deepseek-chat", - messages=[ - {"role": "system", "content": tpl.format(analysis=analysis_str)}, - {"role": "user", "content": raw_input} - ], - temperature=temperature, - max_tokens=max_tokens, - timeout=timeout - ) - result_prompt = (resp2.choices[0].message.content or "").strip() - if not result_prompt: - return jsonify({'code': 500, 'message': '生成失败,请重试', 'data': None}) - try: - db.session.add(Prompt(input_text=raw_input, generated_text=result_prompt, user_id=uid)) - db.session.commit() - except Exception as e: - db.session.rollback() - logger.warning("3号专家 保存 Prompt 失败: %s", e) - try: - PromptHistory.add_history( - user_id=uid, - original_input=raw_input, - generated_prompt=result_prompt, - template_name=TEMPLATE_NAME_3 - ) - UserStatistics.update_statistics(uid) - except Exception as e: - logger.warning("3号专家 保存历史失败: %s", e) - return jsonify({ - 'code': 200, - 'message': 'success', - 'data': {'intent_analysis': intent_data, 'generated_prompt': result_prompt} - }) + result = _do_generate(raw_input, temperature, max_tokens, timeout, uid, skip_dedup=skip_dedup) + return jsonify(result) + except ValueError as e: + return jsonify({'code': 400, 'message': str(e), 'data': None}) except Exception as e: logger.exception("智能提示词优化3号专家失败") return jsonify({'code': 500, 'message': str(e) or '生成失败,请重试', 'data': None})